When declaring template parameters, both class and typename are interchangeable. When identifying nested dependent type names, use typename, except in base class lists or as a base class identifier in a member initialization list.
In template parameter declaration
In the template declarations such as below:
|
|
There’s no difference between these two declarations, though using typename may be helpful to imply that the parameter need not be a class type. From C++’s point of view, class and typename means exactly the same in this case.
Nested dependent type
Names in a template that are dependent on a template parameter are called dependent names. When a dependent name is nested inside a class, we can call it a nested dependent name. For example, considering following code, which actually won’t compile due to the lack of typename:
|
|
In this example, C::const_iterator is not only a dependent name on the template parameter C, but also a nested dependent name, or more specifically, a nested dependent type name (a nested dependent name that refers to a type). As a comparason, local variable value is of type int, independent of any template parameter, which is known as non-dependent name.
The reason why the code above doesn’t compile is that, without typename, it is difficult to parse those nested dependent names. For example, if we make following declaration:
|
|
There are multiple possible ways to interprete this statement:
- We assume
C::const_iteratoris a type, thus we’re declaringxas a local variable that’s a pointer to aC::const_iterator - We assume
Chas a static member that happens to be namedconst_iterator, andxhappens to be the name of a global variable, so this statement is a multiplication ofC::const_iteratorbyx
To resolve this ambiguity, C++ rules that the parser should not assume a nested dependent name in a template as a type, unless we explicitly specify it through typename keyword. Thus, the valid code for the above example should be like this:
|
|
Real world usecase
In real code, it’s representative that sometimes typename shows with another keyword typedef to save some typing time:
|
|
Basically, this statement is to declare a local variable temp of the same type as what IterT objects point to, and it initializes temp with the object that iter points to. Here, the standard traits class (item 47) is to represent the type of thing pointed to by objects of type IterT. For example, if IterT is list<string>::iterator, then temp is of type string. Since value_type is nested inside iterator_traits<IterT>, and IterT is a template parameter, we must precede it by typename.
It is also worth noting that typename should be used to identify only nested dependent type names; other names shouldn’t have it:
|
|
In summary, the general rule is: anytime we refer to a nested dependent type name in a template, we must immediately precede it by the word typename, except for the following two cases:
Exception
There are two exception cases where typename must not precede nested dependent type names:
- in a list of base classes
- as a base class idenfifier in a member initialization list
For example:
|
|
P.S.: Actually, enforcement of the rules surrounding
typenamevary from compiler to compiler. Some compilers accept code wheretypenameis required but missing; some accept code wheretypenameis present but not allowd. This means the interaction oftypenameand nested dependent type names can lead to some portability headaches.