gcc和class关键字

时间:2011-04-18 14:36:11

标签: c++ templates gcc

我知道typenameclass关键字在模板参数中是可互换的,但我认为嵌套类规范只允许typename

一旦我意外地为嵌套类错误地写了“class”而不是“typename”。 我发现gcc也接受class,所以你可以这样写:

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

在你的模板中。

这是一个gcc错误还是标准真的允许这种语法?

更新:代码示例:

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

6 个答案:

答案 0 :(得分:2)

ISO 14886:2003中的第14.6节(“名称解析”)似乎是关于它应该如何工作的定义。第3段说:

  

qualified-id 引用一种类型,其中嵌套名称说明符取决于模板参数(14.6) .2)应以关键字typename作为前缀,以表明 qualified-id 表示类型,形成详细类型说明符(7.1.5.3 )。

未提及class关键字。我认为这是一个GCC错误。

答案 1 :(得分:2)

class a::b是一个精心设计的类型说明符。精心设计的类型说明符的名称查找会忽略非类型名称。因此,如果要解析模板,可以假设两件事:

  • 当我们实例化并对b进行名称查找时,名称查找会给我们一个类型,或者它出错(找不到任何名称)。

出于这个原因,在C ++ 0x中,class a::b不需要typename(你不能把它放在精心设计的类型说明符上的任何地方)。 C ++ 03不允许这样,因此GCC似乎将C ++ 0x规则实现为扩展。

这并不是特别糟糕。每个真正的编译器都代表他们在C ++ 03版本中实现合理且易于实现的规则,即使他们正式需要拒绝它。但是,class a::b 必须查找类名。如果它只是一个typedef,那么详细说明的类型说明符的查找是无效的。

请注意,class a::b是在查找中忽略非类型名称的唯一方法(除了具有类似特殊规则的限定名称中的::之前的神秘案例)。例如

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;

如果编译为C ++ 0x,并且使用class T::type t;,则代码变为有效,因为class T::type忽略数据成员,但查找嵌套类。

答案 2 :(得分:1)

无法使用Comeau Online编译(Comeau C / C ++ 4。3。1。1(2008年10月6日11:28:09)),因此两个编译器中至少有一个有错误。

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

答案 3 :(得分:1)

当然,标准似乎确认应该使用typename。从14.6 / 2开始:

  

假定模板声明或定义中使用的名称取决于模板参数,除非适用的名称查找找到类型名称或名称由关键字typename限定,否则不会命名类型。

答案 4 :(得分:0)

当从属名称未解析为类时,

Ideone显示一条很好的错误消息。因此,您的示例仅有效,因为iterator确实是class。 :)


编辑:即使依赖项确实是一个类,MSVC也无法编译,

  

error C2242:typedef name不能跟随class / struct / union

编辑2 : 这似乎是一个MSVC错误,因为如果依赖名称是一个类,g ++和Comeau online编译就好了。

答案 5 :(得分:-1)

我仍然对失败感到失望。如果把代码放在那里没有问题,我会发表评论。

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

struct X {
    typedef int bb;
};

int main()
{
    f<X>();
    return 0;
}
在实例化期间,

没有使用gcc编译并出错。如果X :: bb是一个类,它将编译。科莫也有同样的行为。

编辑,我想现在我已经有了更好的理解。

class Foo::Bar;

是一个精心设计的类说明符。 Foo :: Bar被查找为限定名称(3.4.4 / 3)。由于它是依赖的,因此必须在实例化期间在第二阶段进行查找。然后,如果找不到它或者它不是类名或枚举名,那么elaborated-class-specifier就是格式错误。

TL; DR g ++似乎没有错误。