class a::b
is an elaborated type specifier. Name lookup for an elaborated type specifier ignores non-type names. So if you are parsing a template, you can assume two things:
- When we are instantiating and do name-lookup for
b
, either name lookup gives us a type, or it errors out (wouldn't find any name).
In C++0x for that reason, class a::b
doesn't need typename
(you can't put it anywhere anyway on a elaborated type specifier). C++03 doesn't allow that, so GCC appears to implement the C++0x rules as an extension.
That's not particularly bad. Every real compiler implements rules that are sensible and easy to implement in their C++03 version, on their behalf, even if formally they would need to reject it. However, class a::b
must lookup to a class name. If it's merely a typedef, then the lookup for the elaborated type specifier is invalid.
Note that class a::b
is the only way to ignore non-type names in a lookup (except for arcane cases like before a ::
in a qualified name that have similar special rules). For example
template<typename T>
struct A { typename T::type t; }
struct B { class type { }; int type; };
// invalid, even though GCC accepts that incorrectly
A<B> a;
If you compile to C++0x, and you use class T::type t;
, then the code becomes valid, because class T::type
ignores the data member, but finds the nested class.