This is the original GotW problem and solution substantially as posted to Usenet. See the book More Exceptional C++ (Addison-Wesley, 2002) for the most current solution to this GotW issue. The solutions in the book have been revised and expanded since their initial appearance in GotW. The book versions also incorporate corrections, new material, and conformance to the final ANSI/ISO C++ standard.

TypenameDifficulty: 9.5 / 10

"What's in a (type) name?" Here's an exercise that demonstrates why and how to use typename, using an idiom that's common in the standard library.

The problem with X is that "instantiated_type" is meant to refer to the typedef supposedly inherited from the base class X_base<B>. Unfortunately, at the time that the compiler has to parse the inlined definition of X<A,B>::operator()(), dependent names (i.e., names that depend on the template parameters, such as the inherited X_Base::instantiated_type) are not visible, and so the compiler will complain that it doesn't know what "instantiated_type" is supposed to mean. Dependent names only become visible later, at the point where the template is actually instantiated.

If you're wondering why the compiler couldn't just figure it out anyway, pretend that you're a compiler and ask yourself how you would figure out what "instantiated_type" means here. Bottom line, you can't figure it out because you don't know what B is yet, and whether later on there might not be a specialization for X_base<B> that makes X_base<B>::instantiated_type something unexpected -- any type name, or even a member variable. In the unspecialized X_base template above, X_base<T>::instantiated_type will always be T, but there's nothing preventing someone from changing that when specializing, for example:

template<>
struct X_base<int> {
typedef Y instantiated_type;
};

Granted, the typedef's name would be a little misleading if they did that, but it's legal. Or even:

template<>
struct X_base<double> {
double instantiated_type;
};

Now the name is less misleading, but template X cannot work with X_base<double> as a base class because instantiated_type is a member variable, not a type name.

Bottom line, the compiler won't know how to parse the definition of X<A,B>::operator()() unless we tell it what instantiated_type is... at minimum, whether it's a type or something else. Here, we want it to be a type.

The way to tell the compiler that something like this is supposed to be a type name is to throw in the keyword "typename". There are two ways we could go about it here. The less elegant is to simply write typename wherever we refer to instantiated_type:

Before reading on, does anything about adding this typedef seem unusual to you?

2. The Secondary (and Subtle) Point

I could have used simpler examples to illustrate this (several appear in the standard in section 14.6.2), but that wouldn't have pointed out the unusual thing: The whole reason the empty base X_base appears to exist is to provide the typedef. However, derived classes usually end up just typedef'ing it again anyway.

Doesn't that seem redundant? It is, but only a little... after all, it's still the specialization of X_base<> that's responsible for determining what the appropriate type should be, and that type can change for different specializations.

The standard library contains base classes like this: "bags-o-typedefs" that are intended to be used in just this way. Hopefully this issue of GotW will help avert some of the questions about why derived classes re-typedef those typedefs, seemingly redundantly, and show that this effect is not really a language design glitch as much as it is just another facet of the age-old question: