Site icon Learn C++

Stages of C++ Templates Compilation On Windows

In order to compile C++ templates the compilers like Embarcadero RAD Studio C++ compilers are required to perform two stages: definition stage and instantiation stage.

The template definition stage

On this stage the following checks are performed:

The complete check of unqualified names is postponed until the template instantiation stage when the template arguments are known.

Please note, since the compilers like Embarcadero RAD Studio C++ performs many checks on this stage a programmer is often see general problems even before the template instantiation stage!

Example of errors even when the branch is discarded at compile-time:

void foo()
{
  if constexpr (false) {
    // Provokes the definition stage
    // error if println is not declared
    println("Borland C++");

    // Always provokes the definition stage error
    static_assert(false);
  }
}

Example of syntax error upon checking of unqualified names which are depends on template parameters:

namespace util {
struct Data {/* ... */};
std::ostream& operator<<(std::ostream&, const Data&);

template<typename T>
void println(T value)
{
  std::cout << value << '\n';
}
} // namespace util

template<typename T>
void out(T value)
{
  // Syntax ok since println() template is declared
  println<T>(value);

  // Provokes syntax error (parsed as "log less-than
  // T ...") since log() template is not declared and
  // the compiler does not know that the less-than
  // token (<) is not less-than operator but the
  // beginning of a template argument list.
  log<T>(value);
}

void foo()
{
  out(util::Data{123});
}

Another example of syntax error upon checking the construct before period that depends on a template parameter:

struct Data {
  template<typename T> T as() const {/* ... */}
};

template<typename T, typename D> T as(const D& data)
{
  // Provokes syntax error since .template construct
  // before "as<T>" is required.
  // Must be: return data.template as<T>();
  return data.as<T>();
}

The template instantiation stage

The first point where the template is used for a first time for particular template arguments is called the point of instantiation. At this point the template arguments are known hence the compilers are able to generate specializations of templates for concrete arguments. During the generation of a specialization:

Please note, that functions and classes generated from templates are subject to the same rules as for regular functions and classes.

Example of errors during the template instantiation stage:

namespace library {
template<typename T>
void print(T value)
{
  // Provokes instantiation stage error if T is
  // neither std::string nor util::Data
  static_assert(std::is_same_v<T, std::string> ||
                std::is_same_v<T, util::Data>);

  // Provokes instantiation stage error if
  // util::println(T) is not defined and called ...
  if constexpr (std::is_same_v<T, std::string>)
    util::println(value); // ... being qualified
  else
    println(value); // ... being unqualified
}
} // namespace library

Exit mobile version