Standard and Non-Standard Template Parsing

CodeWarrior C++ has options to specify how strictly template declarations and instantiations are translated. When using its strict template parser, the compiler expects the typename and template keywords to qualify names, preventing the same name in different scopes or overloaded declarations from being inadvertently used. When using its regular template parser, the compiler makes guesses about names in templates, but may guess incorrectly about which name to use.

A qualified name that refers to a type and that depends on a template parameter must begin with typename (ISO/IEC 14882-2003 C++, §14.6). The following listing shows an example.

Listing: Using the <codeph>typename</codeph> keyword

template <typename T> void f()

{

  T::name *ptr; // ERROR: an attempt to multiply T::name by ptr

  typename T::name *ptr; // OK

}

The compiler requires the template keyword at the end of " ." and " ->" operators, and for qualified identifiers that depend on a template parameter. The following listing shows an example.

Listing: Using the <codeph>template</codeph> keyword

template <typename T> void f(T* ptr)

{

  ptr->f<int>(); // ERROR: f is less than int

  ptr->template f<int>(); // OK

}

Names referred to inside a template declaration that are not dependent on the template declaration (that do not rely on template arguments) must be declared before the template's declaration. These names are bound to the template declaration at the point where the template is defined. Bindings are not affected by definitions that are in scope at the point of instantiation. The following listing shows an example.

Listing: Binding non-dependent identifiers

void f(char);

template <typename T> void tmpl_func()

{

  f(1); // Uses f(char); f(int), below, is not defined yet.

  g(); // ERROR: g() is not defined yet.

}

void g();

void f(int);

Names of template arguments that are dependent in base classes must be explicitly qualified (ISO/IEC 14882-2003 C++, §14.6.2).

Listing: Qualifying template arguments in base classes

template <typename T> struct Base

{

  void f();

}

template <typename T> struct Derive: Base<T>

{

  void g()

  {

    f(); // ERROR: Base<T>::f() is not visible.

    Base<T>::f(); // OK

  }

}

When a template contains a function call in which at least one of the function's arguments is type-dependent, the compiler uses the name of the function in the context of the template definition (ISO/IEC 14882-2003 C++, §14.6.2.2) and the context of its instantiation (ISO/IEC 14882-2003 C++, §14.6.4.2). The following listing shows an example.

Listing: Function call with type-dependent argument

void f(char);

template <typename T> void type_dep_func()

{

  f(1); // Uses f(char), above; f(int) is not declared yet.

  f(T()); // f() called with a type-dependent argument.

}

void f(int);

struct A{};

void f(A);

int main()

{

  type_dep_func<int>(); // Calls f(char) twice.

  type_dep_func<A>(); // Calls f(char) and f(A);

  return 0;

}

The compiler only uses external names to look up type-dependent arguments in function calls.

Listing: Function call with type-dependent argument and external names

static void f(int); // f() is internal.

template <typename T> void type_dep_fun_ext()

{

  f(T()); // f() called with a type-dependent argument.

}

int main()

{

  type_dep_fun_ext<int>(); // ERROR: f(int) must be external.

}

The compiler does not allow expressions in inline assembly statements that depend on template parameters.

Listing: Assembly statements cannot depend on template arguments

template <typename T> void asm_tmpl()

{

  asm { move #sizeof(T), D0 ); // ERROR: Not supported.

}

The compiler also supports the address of template-id rules.

Listing: Address of Template-id Supported

template <typename T> void funcA(T) {}

template <typename T> void funcB(T) {}

...

funcA{ &funcB<int> );     // now accepted