Templates are of great utility to programmers in C++, especially when combined with multiple inheritance and operator overloading. The C++ Standard Template Library (STL) provides many useful functions within a framework of connected templates.

As the templates in C++ are very expressive they may be used for things other than generic programming. One such use is called template metaprogramming, which is a way of pre-evaluating some of the code at compile-time rather than run-time. Further discussion here only relates to templates as a method of generic programming.

There are two kinds of templates. A function template behaves like a function that can accept arguments of many different types. For example, the C++ Standard Template Library contains the function template max(x, y) which returns either x or y, whichever is larger. max() could be defined like this:

This template can be called just like a function:

The compiler determines by examining the arguments that this is a call to max(int, int) and instantiates a version of the function where the type T is int.

There are three primary drawbacks to the use of templates.

  1. First, many compilers historically have very poor support for templates, so the use of templates can make code somewhat less portable.
  2. Second, almost all compilers produce confusing, unhelpful error messages when errors are detected in template code. This can make templates difficult to develop.
  3. Third, each use of a template may cause the compiler to generate extra code (an instantiation of the template), so the indiscriminate use of templates can lead to code bloat, resulting in excessively large executables. The extra instantiations generated by templates can also cause debuggers to have difficulty working gracefully with templates. For example, setting a debug breakpoint within a template from a source file may either miss setting the breakpoint in the actual instantiation desired or may set a breakpoint in every place the template is instantiated.

Default template arguments

The typename keyword

Consider the following:

The template definition assumes that the class T that you hand it must have a nested identifier of some kind called id. But id could be a member object of T, in which case you can perform operations on id directly, but you couldn?t ?create an object? of ?the type id.? However, that?s exactly what is happening here: the identifier id is being treated as if it were actually a nested type inside T. In the case of class Y, id is in fact a nested type, but (without the typename keyword) the compiler can?t know that when it?s compiling X.

If, when it sees an identifier in a template, the compiler has the option of treating that identifier as a type or as something other than a type, then it will assume that the identifier refers to something other than a type. That is, it will assume that the identifier refers to an object (including variables of primitive types), an enumeration or something similar. However, it will not ? cannot ? just assume that it is a type. Thus, the compiler gets confused when we pretend it?s a type.

Because the default behavior of the compiler is to assume that a name that fits the above two points is not a type, you must use typename for nested names, even in places where you think that the compiler ought to be able to figure out the right way to interpret the name on its own. In the above example, when the compiler sees T::id, it knows (because of the typename keyword) that id refers to a nested type and thus it can create an object of that type.

The short version of the rule is: if your type is qualified by a template type parameter, you must use typename.