Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/excel/28.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ typedef改变了含义_C++_Typedef - Fatal编程技术网

C++ typedef改变了含义

C++ typedef改变了含义,c++,typedef,C++,Typedef,当我用g++ template<class T> class A {}; template<class T> class B { public: typedef A<T> A; }; 使用g++一切都可以很好地编译。Clang++3.1不在乎任何一种方式 为什么会这样?第二个行为标准是什么?g++是正确的,并且符合标准。从[3.3.7/1]开始: 类S中使用的名称N应在其名称中引用相同的声明 上下文以及在S.No.的完整范围内重新评

当我用
g++

template<class T>
class A
{};

template<class T>
class B
{
    public:
        typedef A<T> A;
};
使用
g++
一切都可以很好地编译。Clang++3.1不在乎任何一种方式


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

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

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

在typedef之前,
A
指的是
::A
,但是通过使用typedef,现在可以使
A
指的是禁止使用的typedef。但是,由于
不需要诊断
,因此clang也是符合标准的

解释此规则的原因。 对代码进行以下更改:

template<class T>
class A
{};

template<class T>
class B
{
    public:
        A a; // <-- What "A" is this referring to?
        typedef     A<T>            A;
};
模板
甲级
{};
模板
B类
{
公众:

A;//我将补充Jesse关于GCC在编译过程中看似奇特的行为的回答:

typedef A<T> A;
typedef A;
vs

typedef::A;
这也适用于使用以下形式的语句:

using A =   A<T>;
using A = ::A<T>;
使用A=A;
使用A=::A;
在GCC中似乎发生的事情是,在编译声明B::A的typedef/using语句的过程中,符号B::A在using语句本身中成为一个有效的候选者。即,当使用A=A说
时;
typedef A;
GCC同时考虑
:A
B::A
A
的有效候选项

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


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

它必须是警告级别,默认情况下显示为错误。这与您可能有一个函数缺少返回,并且可以报告为错误或警告一样。通常,我会避免将A类型声明为错误答a。以后会很混乱。我不知道标准怎么说,但我很高兴g++抱怨…这很愚蠢。我认为这既不愚蠢,也不混乱。我经常遇到这个问题。至于警告到错误转换,我没有给g++任何标志,默认情况下它会转换成错误什么警告?这实际上有点奇怪b更高。如果在声明本地
a
之前使用了全局级别
a
,则会发生此错误。也就是说,使用
a
(声明成员)在
typedef::A
之前,将产生相同的错误。移动下面的声明将
A
更改为本地声明并修复错误。与
typedef A A
相同,您在“左侧”之前使用全局
A
,然后立即“右侧”重新声明。这只是g++确保类中所有出现的
A
都具有相同的含义(不是
::A
,这不会改变)@foxcub:在第二种形式中,你指的不是
A
,你指的是
::A
。第二种形式是正确的。很有趣,但仍然很神秘。为什么变化的含义不一样?在typedef之前,它的意思与::A相同,即模板类。在typedef之后,它意味着一个非常具体的类,一个特定的insta注意::A,即::A。我很高兴听到第二种形式是正确的,但请帮助我理解。foxclub是正确的,GCC处理这个问题的方式有些奇怪。首先,
typedef::A
确实改变了
A
的含义,就像
typedef A
一样。其次,如果你这样做
typedef int X;
的话全局级别,然后是类定义中的
typedef float X;
,这会更改
X
的含义,但没有任何问题。使用typedef在单独的作用域(在本例中为类作用域)中重新定义名称的含义是完全正确的。(当然这也会让人困惑,我不建议你这么做。)@JesseGood(关于第一条评论)我同意这个词的意思很模糊,在这个上下文中可能不合适。但是,如果你做了
typedef::A;
,然后再做(例如,在成员函数中的某个地方,可能在类定义之外)执行
A;
,则此
A
将引用类型名
::A
,不再引用模板名
::A
,因此它已更改。或者可能我误解了在这种情况下引用的含义。@JesseGood(关于Ideone示例)是的!实际上,这个例子就是我认为标准引用的内容:
X
在类中被定义为
float
,这是因为类的作用域是如何工作的(这就是§3.3.7/1的内容),该定义必须扩展到整个类范围,包括单独定义的成员函数,并包括在实际typedef之前找到的任何内容。因此声明
X
变得模棱两可。(如果有
typedef::A A;
并放置成员
A;
(或
A;
)在typedef之前。)
typedef A<T> A;
typedef ::A<T> A;
using A =   A<T>;
using A = ::A<T>;