Versions 2.5 and later of Carbide.c++ enforces the ISO C++ standard more closely when translating templates than previous versions of Carbide.c++. By default this new template translation is off. To ensure that template source code follows the ISO C++ standard more closely, turn on the ISO C++ Template Parser option .
The compiler provides pragmas to help update your source code to the more conformant template features. The parse_func_templ pragma controls the new template features. The parse_mfunc_templ pragma controls the new template features for class member functions only. The pragma warn_no_typename warns for the missing use of the typename keyword required by the ISO C++ standard.
When using the new template parsing features, the compiler enforces more careful use of the typename and template keywords, and follows different rules for resolving names during declaration and instantiation than before.
A qualified name that refers to a type and that depends on a template parameter must begin with typename (ISO C++, §14.6). An example using the 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. An example using the 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. Listing 1 shows an example.
void f(char);
template <typename T> void tmpl_func()
{
f(1); // Uses f(char); f(int) 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 C++, §14.6.2). See Listing 2.
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 C++, §14.6.2.2) and the context of its instantiation (ISO C++, §14.6.4.2). Listing 3 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.
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.
template <typename T> void asm_tmpl()
{
asm { move #sizeof(T), D0 ); // ERROR: Not yet supported.
}
The compiler also supports the address of template-id rules.
template <typename T> void foo(T) {}
template <typename T> void bar(T) {}
...
foo{ &bar<int> ); // now accepted