Bruce Eckel's Thinking in C++, 2nd Ed Contents | Prev | Next

The typename keyword

Consider the following:

//: C19:TypenamedID.cpp
// Using 'typename' to say it's a type, 
// and not something other than a type

template<class T> class X {
  // Without typename, you should get an error:
  typename T::id i;
public:
  void f() { i.g(); }
};

class Y {
public:
  class id {
  public:
    void g() {}
  };
};

int main() {
  Y y;
  X<Y> xy;
  xy.f();
} ///:~

The template definition assumes that the class T that you hand it must have a nested identifier of some kind called id. But id could be a member object of T, in which case you can perform operations on id directly, but you couldn’t “create an object” of “the type id.” However, that’s exactly what is happening here: the identifier id is being treated as if it were actually a nested type inside T. In the case of class Y, id is in fact a nested type, but (without the typename keyword) the compiler can’t know that when it’s compiling X.

If, when it sees an identifier in a template, the compiler has the option of treating that identifier as a type or as something other than a type, then it will assume that the identifier refers to something other than a type. That is, it will assume that the identifier refers to an object (including variables of primitive types), an enumeration or soemthing similar. However, it will not – cannot – just assume that it is a type. Thus, the compiler gets confused when we pretend it’s a type.

The typename keyword tells the compiler to interpret a particular name as a type. It must be used for a name that:

  1. Is a qualified name, one that is nested within another type.
  2. Depends on a template argument. That is, a template argument is somehow involved in the name. The template argument causes the ambiguity when the compiler makes the simplest assumption: that the name refers to something other than a type.
Because the default behavior of the compiler is to assume that a name that fits the above two points is not a type, you must use typename even in places where you think that the compiler ought to be able to figure out the right way to interpret the name on its own. In the above example, when the compiler sees T::id, it knows (because of the typename keyword) that id refers to a nested type and thus it can create an object of that type.

The short version of the rule is: if your type is a qualified name that involves a template argument, you must use typename.

Typedefing a typename

The typename keyword does not automatically create a typedef. A line which reads:

typename Seq::iterator It;

causes a variable to be declared of type Seq::iterator. If you mean to make a typedef, you must say:

typedef typename Seq::iterator It;

Using typename instead of class

With the introduction of the typename keyword, you now have the option of using typename instead of class in the template argument list of a template definition. This may produce code which is clearer:

//: C19:UsingTypename.cpp
// Using 'typename' in the template argument list

template<typename T> class X { }; 

int main() {
  X<int> x;
} ///:~

You’ll probably see a great deal of code which does not use typename in this fashion, since the keyword was added to the language a relativly long time after templates were introduced.

Contents | Prev | Next


Contact: webmaster@codeguru.com
CodeGuru - the website for developers.
[an error occurred while processing this directive]