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_iterator
is a type, thus we’re declaringx
as a local variable that’s a pointer to aC::const_iterator
- We assume
C
has a static member that happens to be namedconst_iterator
, andx
happens to be the name of a global variable, so this statement is a multiplication ofC::const_iterator
byx
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
typename
vary from compiler to compiler. Some compilers accept code wheretypename
is required but missing; some accept code wheretypename
is present but not allowd. This means the interaction oftypename
and nested dependent type names can lead to some portability headaches.