当我用g++
编译以下代码片段时
template<class T>
class A
{};
template<class T>
class B
{
public:
typedef A<T> A;
};
编译器告诉我
error: declaration of ‘typedef class A<T> B<T>::A’
error: changes meaning of ‘A’ from ‘class A<T>’
另一方面,如果我将typedef
更改为
typedef ::A<T> A;
使用g++
可以很好地编译所有内容。无论哪种方式,Clang++ 3.1都不在乎。
为什么会发生这种情况?第二个行为标准是什么?
发布于 2012-08-30 07:07:22
g++是正确的,并且符合标准。来自3.3.7/1
在S级中使用的A名称N应在其上下文中引用相同的声明,并且在S的完整范围内重新评估时,不需要对违反本规则的情况进行诊断。
在类型定义函数之前,A
引用了::A
,但是通过使用类型定义函数,您现在使A
引用禁止的类型定义函数。然而,由于no diagnostic is required
,clang也是符合标准的。
jogojapan's comment解释了此规则的原因。对您的代码进行以下更改:
template<class T>
class A
{};
template<class T>
class B
{
public:
A a; // <-- What "A" is this referring to?
typedef A<T> A;
};
由于类作用域的工作方式,A a;
变得不明确。
发布于 2014-01-31 02:47:39
我将补充杰西的回答,关于GCC在编译过程中看似奇怪的行为:
typedef A<T> A;
vs
typedef ::A<T> A;
这也适用于使用以下形式的语句:
using A = A<T>;
using A = ::A<T>;
在GCC内部似乎发生的事情是,在编译声明B::A的typedef/using语句期间,符号B::A成为using语句本身中的有效候选。也就是说,当说using A = A<T>;
或typedef A<T> A;
时,GCC认为::A
和B::A
都是A<T>
的有效候选者。
这似乎是一种奇怪的行为,因为正如您的问题所暗示的那样,您不希望新的别名A成为typedef本身内的有效候选者,但正如Jesse的回答所说的那样,在类中声明的任何内容对类中的其他所有内容都是可见的-在这种情况下,显然甚至包括声明本身。这种类型的行为可以以这种方式实现,以允许递归类型定义。
正如您所发现的,解决方案是为GCC精确地指定您在typedef中引用的A,然后它就不再抱怨了。
https://stackoverflow.com/questions/12187549
复制相似问题