Return Styles: Pseud0ch, Terminal, Valhalla, NES, Geocities, Blue Moon. Entire thread

Sepplesfags, help!

Name: Anonymous 2008-12-08 18:34


template <class T>
class A
{
public:
    typedef T Foo;
};

template <class T>
class B
{
    A<T>::Foo foo;
};

int main()
{
    B<int> b;
    return 0;
}



test.cpp:11: error: type ‘A<T>’ is not derived from type ‘B<T>’
test.cpp:11: error: expected ‘;’ before ‘foo’


What the FUCK?

Name: Anonymous 2008-12-09 13:54

>>15
Stolen from: Thinking in C++, vol.2, Ch.6, The typename keyword
Consider the following:

    //: C06:TypenamedID.cpp
    // Using 'typename' to say it's a type,
    // and not something other than a type
    //{L} ../TestSuite/Test

    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  [code]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  Yid 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 something 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.

Newer Posts
Don't change these.
Name: Email:
Entire Thread Thread List