I've gotten quite used to the obligatory use of typename
in class-templates, but can't help but wonder if if it's really necessary. This question was asked before here on SO, but I wasn't quite satisfied with the answers (and neither was the OP if I understood correctly).
The when and where is perfectly clear (from cppreference.com):
In a declaration or a definition of a template, including alias template, a name that is not a member of the current instantiation and is dependent on a template parameter is not considered to be a type unless the keyword typename is used or unless it was already established as a type name, e.g. with a typedef declaration or by being used to name a base class.
When a (class- or function-)template is defined (not instantiated yet), I understand that the statement
A::Type *tp;
where A
is a template type-parameter and Type
should be a nested type, is ambiguous. Type
might as well be a static member or enum value, or whatever other possibilities there are that I can't think of right now. The *
operator in this case is a multiplication (assuming "multiplication" is the correct wording for the implementation of operator*()
) rather than a pointer declaration. I can't, however, think of any situation where such a statement could represent a multiplication in class scope. In function-scope, sure, but what could this mean in class-scope other than a pointer declaration?
My point being that in many cases the compiler expects a typename at some point, but still demands from us that we explicitly specify this, even though there are no other options. The fact that GCC and Clang both emit an error rather than a warning is pretty illustrative:
template <typename T>
struct A
{
T::x *p;
};
GCC: error: need ‘typename’ before ‘T::x’ because ‘T’ is a dependent scope
CLANG: error: missing 'typename' prior to dependent type name 'T::x'
Another compelling case (to me at least) is when using typedef
s to alias dependent types. In this case, there is no doubt about whether whatever follows the typedef
keyword should be a type (right?), so why disambiguate anything?
To summarize: in the many cases where the compiler can easily deduce from the syntax and context whether the programmer means a type or variable, why is it still necessary to disambiguate?
EDIT
The comments and the suggested duplicate mention that specializations might complicate matters. For example (taken from an answer in the other thread):
struct B {
typedef int result_type;
};
template<typename T>
struct C { }; // could be specialized!
template<typename T>
struct D : B, C<T> {
void f() {
// OK, member of current instantiation!
// A::result_type is not dependent: int
D::result_type r1;
// error, not a member of the current instantiation
D::questionable_type r2;
// OK for now - relying on C<T> to provide it
// But not a member of the current instantiation
typename D::questionable_type r3;
}
};
I understand that C
might be specialized for T
, and whether C<T>::questionable_type
exists can only be resolved on instantiation, but this doesn't change the fact that it has to be a type. The syntax is just demands it, so why disambiguate?