我知道typename
和class
关键字在模板参数中是可互换的,但我认为嵌套类规范只允许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;
}
答案 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 ++似乎没有错误。