Effective C++ item 42: Understand the Two Meanings of typename

Ever wonder why you need to specify typename when you use nested dependent type name? Consider following example without typename

1
2
3
4
5
6
template<typename C>
void print2nd(const C& container)
{
C::const_iterator * x;
...
}

This looks like we’re declaring x as a local variable that’s a pointer to a C::const_iterator. But it looks that way only because we “know” that C::const_iterator is a type. But what if C::const_iterator weren’t a type? What if C had a static data member that happened to be named const_iterator, and what if x happened to be the name of a global variable? In that case, the code above wouldn’t declare a local variable, it would be a multiplication of C::const_iterator by x!

This is exactly why typename is needed before nested dependent type - to avoid ambiguity. Now let’s look at two special cases that we don’t need typename, because it won’t have such ambiguity.

1
2
3
4
5
6
7
8
9
10
11
template<typename T>
class Derived: public Base<T>::Nested { // base class list: typename not
public: // allowed
explicit Derived(int x)
: Base<T>::Nested(x) // base class identifier in mem
{ // init. list: typename not allowed
typename Base<T>::Nested temp; // use of nested dependent type
... // name not in a base class list or
} // as a base class identifier in a
... // mem. init. list: typename required
};

A practical way of specifying long nested type name is by typedef it

1
2
3
4
5
6
7
template<typename IterT>
void workWithIterator(IterT iter)
{
typedef typename std::iterator_traits<IterT>::value_type value_type;
value_type temp(*iter);
...
}

Last point of typename: when declaring template parameters, class and typename are interchangeable.

Reference:
“Effective C++” Third Edition by Scott Meyers.