开发者

gcc and class keyword

I know that typename and class keywords are interchangeable in template arguments, but I thought only typename is allowed for nested classes specification.

Once I've accidentally wrote incorrectly "class" instead of "typename" for a nested class. And I found is that gcc accepts class there too, so you can write something like:

class std::vector<T>::iterator it;
instead of
typename std::vector<T>::iterator it;

in your template.

Is this a gcc bug or does the standard really allow t开发者_如何转开发his syntax?

UPDATE: example of code:

template <typename T>
void test()
{
     class std::vector<T>::iterator it;
}


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.


Section 14.6 ("Name resolution") in ISO 14886:2003 seems to be the definition of how this is supposed to work. Paragraph 3 says:

A qualified-id that refers to a type and in which the nested-name-specifier depends on a template-parameter (14.6.2) shall be prefixed by the keyword typename to indicate that the qualified-id denotes a type, forming an elaborated-type-specifier (7.1.5.3).

No mention of the class keyword. I think this is a GCC bug.


It fails to compile with Comeau Online (Comeau C/C++ 4.3.10.1 (Oct 6 2008 11:28:09)), so at least one of the two compiler has a bug.

error: typedef "iterator" may not be used in an elaborated
          type specifier
       class std::vector<T>::iterator it;


Certainly the Standard seems to confirm that typename should be used. From 14.6/2:

A name used in a template declaration or definition and that is dependent on a template-parameter is assumed not to name a type unless the applicable name lookup finds a type name or the name is qualified by the keyword typename.


Ideone shows a nice error message when the dependent name doesn't resolve to a class. So your example only works because iterator is indeed a class. :)


Edit: MSVC fails to compile even if the dependent is indeed a class,

error C2242: typedef name cannot follow class/struct/union

Edit 2: This seems to be a MSVC bug, as g++ and Comeau online compile just fine if the dependent name is a class.


I'm still loss at what happen. I'd put a comment if putting code there wasn't problematic.

template <typename Foo>
void f()
{
    class Foo::bb x;
}

struct X {
    typedef int bb;
};

int main()
{
    f<X>();
    return 0;
}

doesn't compile with gcc with an error during the instantiation. It will compile if X::bb is a class. Como has the same behavior.

Edit, I think I've a better understanding now.

class Foo::Bar;

is an elaborated-class-specifier. Foo::Bar is looked up as a qualified name (3.4.4/3). As it is dependent, the look-up has to be done in the second phase, during instantiation. Then if it isn't found or if it isn't a class-name or enum-name, the elaborated-class-specifier is ill-formed.

TL;DR g++ doesn't seem to have a bug.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜