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). Using the typename keyword shows an example.
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. Using the template keyword shows an example.
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. Binding non-dependent identifiers shows an example.
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 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). Function call with type-dependent argument shows an example.
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 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 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. See Address of Template-id Supported.
template <typename T> void funcA(T) {}
template <typename T> void funcB(T) {}
...
funcA{ &funcB<int> ); // now accepted