Why you need typename
Tuesday, January 20th, 2009One of our PhD students had problems with C++ today and asked me for help.
He had a piece of code that, for this post, can be reduced to this:
#include <vector>
template <typename T>
class C {
void foo(std::vector<t>::iterator i);
};
If you are an experienced C++ programmer, it doesn’t take you long to see the problem here, but if you are not, this piece of code looks perfectly valid and the error message you get from g++
test.cc:6: error: ‘class std::vector<T, std::allocator<_CharT> >::iterator’ is not a type test.cc:7: error: expected unqualified-id at end of input
is of no help at all.
Why isn’t vector<T>::iterator a type? It always is!
Well, the thing is, that is not actually guaranteed.
Another example that shows the problem might make it clearer.
template <typename T>
struct C {
int p;
void foo()
{
T::t * p;
}
};
In foo, are we defining p as a pointer to a T::t, or are we just multiplying a static member T::t with the instance variable p?
You cannot know that before you know T, and to get around that problem, the C++ standard requires that you make types explicit using the typename keyword. If you don’t, it will assume that you mean a static member. So you should change the example to this:
template <typename T>
struct C {
int p;
void foo()
{
typename T::t * p;
}
};
What about the vector example, then? Surely a vector<T>::iterator is always a type?
No, actually not. You can always specialize a template like vector<T> and for example say that a vector of class C has a static member named iterator, instead of a typedef.
Think about vector<bool>. That is a specialization, and is different from what the generic vector<T> would be, if it had been instantiated with T=bool.
Until the point where a template is instantiated, you really know very little about it, so you need to help the compiler.
The fix to the original problem is just adding the typename keyword:
#include <vector>
template <typename T>
class C {
void foo(typename std::vector<t>::iterator i);
};
–
20-36=-16