Details, Details.

C++ templates are tricky.

In C++ you can declare typedefs inside of classes or class templates, and then you can use them to make your life a little easier. Well, mainly it’s easier with classes; templates make you jump through some extra hoops.

When you have a typedef inside a class template and you need to refer to it, C++ isn’t smart enough to know whether you are referring to a type or a member, so it just assumes you are referring to a member. You have to use the typename keyword to inform C++ when this isn’t the case.

Here is some code I came across today:

    template <typename T>
    class Widget {
    public:
        // Type of widget IDs!
        typedef int WidgetID;

        // Returns the widget's ID.
        WidgetID widgetID() const;
    };

    template <typename T>
    inline Widget<T>::WidgetID Widget<T>::widgetID() const {
        return . . . ;
    }

The first point of note is that WidgetID has no dependency on the template parameters at all, so why not move it outside the class template? That makes things easier for everybody involved. The biggest reason to do that is that WidgetID is used as a return type, and member function return types are not considered to be within the scope of the class! So, WidgetID requires a prefix of Widget<T>:: just to use it as a return type, because we wanted to be slick and use a typedef inside our class template.

(Another note is that this function naming convention is not recommended. When symbol names differ only in capitalization, it’s just asking for confusing compiler errors!)

Of course, the main issue is that this code won’t even compile! The reason why is that the compiler assumes that Widget<T>::WidgetID refers to a data member, even though we can clearly see that it’s a type. So, the compiler needs a little hint:

    template <typename T>
    inline typename Widget<T>::WidgetID Widget<T>::widgetID() const {
        return . . . ;
    }

In this context, the typename keyword tells the compiler that the next specifier refers to a type, not a data-member.

This is a bit of an esoteric aspect of the C++ language, but it was surprisingly important for me today.

One Response to “Details, Details.”

  1. mason Says:

    I’ve been using that trick in a lot of my code for my current project. I actually used it to typedef vector::iterator as something shorter. It works fine under MSVC++.NET, but not with g++. I think it’s because I don’t use typename with it. MS is known to be non-compliant with ANSI, especially with templates, so I guess I just found out the hard way.

Leave a Reply