Skip to content

Last updated:2026-10-12

STL typename source code analysis

There are a few lines like the following in the underlying STL source code, with typedef used together with typename. They look quite complicated. What exactly do they mean? Let's dissect them together today!

template<typename _Iterator>
struct iterator_traits
{
  typedef typename _Iterator::iterator_category iterator_category;
  typedef typename _Iterator::value_type        value_type;
  typedef typename _Iterator::difference_type   difference_type;
  typedef typename _Iterator::pointer           pointer;
  typedef typename _Iterator::reference         reference;
};

Common usage of typename

First, let's learn the common usage of typename:

template <typename T>
int compare(const T &a, const T &b)
{
    return a>b?a:b;
}

The above is just a sample program; to write a complete comparison, you would also need to consider specialized versions. You might think that replacing typename with class in the code above works just as well — right! So here comes the question: is there any difference between the two? After consulting C++ Primer, it turns out they are exactly the same.

Class scope

When accessing names inside a class from outside the class, you can use the class scope operator. Calls of the form MyClass::name usually come in three kinds: static data members, static member functions, and nested types:

struct MyClass {
    static int A; //静态成员
    static int B(){cout<<"B()"<<endl; return 100;} //静态函数
    typedef int C;  //嵌套类型
    struct A1 { //嵌套类型
        static int s;
    };
};

When calling, you can call directly:

cout<<MyClass::A<<endl;
cout<<MyClass::B()<<endl;
MyClass:C c;
...

A complete example

Let's return to a typename example:

template <class T>
void foo() {
    T::iterator * iter;
    // ...
}

What is the purpose of this code? Most people's first reaction might be: the author wants to define a pointer iter whose type is the iterator contained in the class scope T. There could be a structure containing an iterator type like this:

struct MyIterator {
    struct iterator {

    };
};

Called as follows:

foo<MyIterator>();

This way, the iter line is clear: it is a pointer of type MyIterator::iterator. That is our guess — but is it what actually happens?

But what about something like T::iterator? T is a type parameter in a template; which type it is will only be known when the template is instantiated, let alone the iterator inside it. From the introduction to class scope above, we know that T::iterator could in fact be any of the following three kinds:

  • static data member
  • static member function
  • nested type

The ContainsAType::iterator in the previous example is a nested type, which is perfectly fine. But what if it is a static data member? What if the type used to instantiate the foo template function looks like this:

struct MyIterator {
    static int iterator;
};

Then T::iterator * iter; is instantiated by the compiler as MyIterator::iterator * iter; — what is this? The leading part is a static member variable rather than a type, so this becomes a multiplication expression, except that iter is not defined here, and the compiler reports an error:

error: no type named ‘iterator’ in ‘struct MyIterator’

typename

For a name used inside a template definition that depends on a template parameter, the compiler will treat the name as a type only if that type name exists among the instantiation arguments, or if the name is preceded by the typename keyword. Apart from these two cases, it will never be treated as a type.

Therefore, if you want to tell the compiler directly that T::iterator is a type and not a variable, you only need to qualify it with typename:

template <class T>
void foo() {
    typename T::iterator * iter;
}

This way the compiler can determine that T::iterator is a type without having to wait until instantiation, thereby eliminating the ambiguity mentioned earlier.

Dissecting the source code

Back to the STL source code

template<typename _Iterator>
struct iterator_traits
{
  typedef typename _Iterator::iterator_category iterator_category;
  typedef typename _Iterator::value_type        value_type;
  typedef typename _Iterator::difference_type   difference_type;
  typedef typename _Iterator::pointer           pointer;
  typedef typename _Iterator::reference         reference;
};

Seeing the above, it becomes clear at once: it is nothing more than using typename to tell the compiler that _Iterator::iterator_category is a type, then using typedef to rename it — the rest is similar!

Comments