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 typename 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 template 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). See the following listing.

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. See the following listing.

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. See the following listing.

Listing: Unsupported Template Parameters
template <typename T> void asm_tmpl()
{
  asm { move #sizeof(T), D0 ); // ERROR: Not supported.
}

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

Listing: Address of Template-id Supported
template <typename T> void funcA(T) {}
template <typename T> void funcB(T) {}
...

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