Reputation: 661
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
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