8

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 this syntax?

UPDATE: example of code:

template <typename T>
void test()
{
     class std::vector<T>::iterator it;
}
rip
  • 83
  • 4
  • 1
    why don't you post the code? and which version of gcc? – Nawaz Apr 18 '11 at 14:38
  • it works for any usage of class instead of typename. I tried this on gcc 4.1.2 and 4.3.4 – rip Apr 18 '11 at 14:52
  • possible duplicate of [What is the difference between "template " and "template "?](http://stackoverflow.com/questions/4534313/what-is-the-difference-between-template-class-t-and-template-typename-t) – rubenvb Apr 18 '11 at 15:01
  • @rubenvb: Nah, this is about the `typename` before nested type(def)s. – Xeo Apr 18 '11 at 15:03
  • @Xeo: is there a fundamental difference? I also found the typename<->class thing fishy, and never got a full and complete answer. – rubenvb Apr 18 '11 at 15:04
  • @rubenvb: Yes, there is a difference. In template declarations, they are indeed interchangeable. Not for nested types though. – Xeo Apr 18 '11 at 15:07
  • This question might be clearer if you used the correct terminology: "dependent name" (rather than "nested class"). – Ben Voigt Apr 18 '11 at 15:09

6 Answers6

2

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.

Wyzard
  • 33,849
  • 3
  • 67
  • 87
  • thanks, so this should be a bug like I suspected. I'll check it with the most recent gcc version and will report this bug if it is still there. – rip Apr 18 '11 at 15:42
2

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.

Johannes Schaub - litb
  • 496,577
  • 130
  • 894
  • 1,212
  • so this is a c++0x extension? ok, good to know that. However it is a bit strange that it is enabled by default. – rip Apr 22 '11 at 09:36
1

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;
Sylvain Defresne
  • 42,429
  • 12
  • 75
  • 85
1

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.

0

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.

Xeo
  • 129,499
  • 52
  • 291
  • 397
-1

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.

AProgrammer
  • 51,233
  • 8
  • 91
  • 143