typedef改变了含义

typedef changes meaning

本文关键字:改变 typedef      更新时间:2023-10-16

当我用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;

用CCD_ 3编译一切都很好。Clang++3.1不管怎样都不在乎。

为什么会发生这种情况?第二种行为标准是什么?

g++正确且符合标准。来自[3.3.7/1]:

S类中使用的名称N应在其上下文以及在S.No的完整范围内重新评估时违反此规则需要进行诊断。

在typedef之前,A引用::A,但是通过使用typedef,现在可以使A引用被禁止的typedef。然而,由于no diagnostic is required,clang也是符合标准的。

日本政府的评论解释了这一规定的原因。对您的代码进行以下更改:

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;变得不明确。

我将添加到Jesse关于GCC在编译中看似特殊的行为的回答中:

typedef A<T> A;

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,然后它就不再抱怨了。