sperber
sperber

Reputation: 661

Why does the C++ compiler require a "typename" keyword in this particular case?

I just figured out that C++ requires a typename in the following code (see the member function definition at the end of the code fragment):

template <typename T> struct ClassWithSubtype
{
    struct Sub
    {
        //static void check( const ClassWithSubtype<T>::Sub& sub );
        ClassWithSubtype<T>::Sub& operator=( const ClassWithSubtype<T>::Sub& other );
    };
};

/*
//Here C++ does not require a typename for the argument type
template <typename T> void ClassWithSubtype<T>::Sub::check( const ClassWithSubtype<T>::Sub& sub )
{
    //do sth.
}
*/

//Here C++ requires a typename for the return type
template <typename T> typename ClassWithSubtype<T>::Sub& ClassWithSubtype<T>::Sub::operator=( const ClassWithSubtype<T>::Sub& other )
{
    //do sth.
}

I can completely understand that C++ requires the keyword typename for the return type. What I do not understand is why NO typename is needed for the argument type of the example function check (which is commented out). Furthermore, why is a typename required in the definition of the assignment operator, but not in its declaration?

Upvotes: 0

Views: 124

Answers (1)

Ben Voigt
Ben Voigt

Reputation: 283901

These two rules together (both in 14.6.2.1) yield the observed behavior:

First, that

A name refers to the current instantiation if it is

  • in the definition of a class template, a nested class of a class template, a member of a class template, or a member of a nested class of a class template, the injected-class-name (Clause 9) of the class template or nested class,

  • in the definition of a primary class template or a member of a primary class template, the name of the class template followed by the template argument list of the primary template (as described below) enclosed in <> (or an equivalent template alias specialization),

  • in the definition of a nested class of a class template, the name of the nested class referenced as a member of the current instantiation, or

and one more unrelated bullet point.

Then,

A name is a member of the current instantiation if it is

  • An unqualified name that, when looked up, refers to at least one member of a class that is the current instantiation or a non-dependent base class thereof. [ Note: This can only occur when looking up a name in a scope enclosed by the definition of a class template. — end note ]

and two unrelated bullet points.

Therefore, in both cases, ClassWithSubType<T> refers to the current instantiation. But as the note explains, Sub refers to a member of the current instantiation only when used inside the class template body. In the out-of-class definition, it becomes a "member of an unknown specialization".

As a member of the current instantiation, the compiler determines that Sub is a class type.

Outside the class body, the compiler doesn't know this and the typename keyword is needed.

Upvotes: 2

Related Questions