2012-08-29 98 views
18

当我编译g++typedef的变化意味着

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不关心任何一种方式。

这是怎么发生的?并且是第二个行为标准?

+1

它必须是警告级别,默认情况下显示为错误。与你可以有一个功能缺失返回一样,可以报告为错误或警告。一般来说,我会避免宣布A型为A 。这会在以后引起混淆。 – Grzegorz

+0

我不知道这个标准说了些什么,但我很高兴g ++抱怨说......这很愚蠢。 –

+0

我认为这既不愚蠢也不混淆。我经常遇到这个问题。至于警告错误转换,我不给g ++任何标志,默认情况下会转换为错误的警告? – foxcub

回答

10

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

需要在一个S类使用的,应当是指相同的声明在其 上下文,并且当重新评估在S.否 诊断的完成范围甲名称为N违反此规定。

typedef的之前,A提到了::A,但使用的typedef,你现在做A指的是禁止的typedef。但是,由于no diagnostic is required,铿锵也符合标准。

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;变得模糊。

+0

第二种形式如何?它也是一个错误,而g ++根本不报告它? – foxcub

+3

@foxcub:在第二种形式中,你不是指'A',而是指':: A'。第二种形式是正确的。 –

+0

@foxclub:第二种形式没问题(正如Kevin Ballard解释的那样),因为'A'的含义不会改变。 –

1

我会编制增加杰西的关于GCC看似奇特的行为答案:

typedef A<T> A; 

VS

typedef ::A<T> A; 

这也适用于使用报表以及形式:

using A = A<T>; 
using A = ::A<T>; 

GCC内部似乎正在发生什么,是在编译typedef/u歌唱声明B :: A,符号B :: A成为使用声明本身内的有效候选。即当说using A = A<T>;typedef A<T> A; GCC考虑A<T>有效的候选人::AB::A

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

您发现的解决方案是为GCC指定一个您在typedef中引用的A,然后它不再抱怨。