Why you need typename

One 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

Tags: ,

Leave a Reply