If you slightly change your declaration, you get an entire different story
template <class T>
void foo(T::type& v);
That isn't unambiguous anymore. It could declare a variable of type void
that is initialized by a bit-wise AND
expression. The entire declaration would be templated. Of course, this semantically is all nonsense, but it syntactically is alright.
The appearance of a single const
syntactically makes it unambiguous, but it's too much context dependence to make this work in a compiler. It has to remember that it read a const
or any other such thing, and when it parses the T::type
after it will need to remember to take this name as a type. It would also further bloat the already complicated Standard beyond belief.
Let's again change your function declaration
template <class T>
void foo(const T::type);
Not even the appearance of const
in there provides for a unambiguous parse. Should it be a function declaration with an unnamed parameter, or should it be a function declaration with an invalid parameter name that misses its type? A parameter's name is parsed by a declarator-id
, which can also be a qualified name. So here, the const
will belong to the type specifiers, while the T::type
will be parsed by the compiler as the name of the parameter, in absence of a typename
. That is totally nonsense too, but is syntactically valid.
In the case of base-class names name lookup itself states that non-type names are ignored. So you get omission of typename
for free: The name that name lookup yields to more higher level modules of the compiler either refers to a type, or name lookup will have given an error.
I have written a FAQ entry about Where to put the "template" and "typename" on dependent names.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…