typedef改变了意义

时间:2012-08-29 22:47:58

标签: c++ typedef

当我使用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并不关心。

为什么会这样?并且是第二个行为标准吗?

2 个答案:

答案 0 :(得分:10)

g ++是正确的,符合标准。从[3.3.7 / 1]开始:

  

类S中使用的名称N应引用其中的相同声明   上下文,并在完成范围内重新评估   违反此规则需要诊断。

在typedef之前,A引用了::A,但是通过使用typedef,你现在让A引用被禁止的typedef。但是,由于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;变得模棱两可。

答案 1 :(得分:1)

我将补充Jesse关于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会同时考虑::AB::A A<T>的有效候选人。

这似乎很奇怪,因为正如你的问题暗示的那样,你不希望新的别名A成为typedef本身的有效候选者,但正如Jesse的回答所说,在一个类中声明的任何内容都可以被其他内容看到这个类 - 在这种情况下显然甚至是声明本身。这种行为可以通过这种方式实现,以允许递归类型定义。

您找到的解决方案是为GCC精确指定您在typedef中引用的A,然后它不再抱怨。