为什么结构的typedef-name不能与结构名称互换使用?

时间:2015-03-29 23:36:12

标签: c++ language-lawyer

以下代码(live example)无法编译:

struct S {};
typedef struct S T;
S s = T();          // OK
struct T * p;       // error: elaborated type refers to a typedef
T::T(){}            // error: C++ requires a type specifier for all declarations

为什么语言设计为不允许最后两行?


相关标准报价(N4140§7.1.3/ 8):

  

[注意:命名类类型或其cv限定版本的 typedef-name 也是类名(9.1)。   如果 typedef-name 用于标识 elaborated-type-specifier (7.1.6.3)的主题,类定义(第9节),构造函数声明( 12.1)或析构函数声明(12.4),该程序格式错误。    - 后注]

1 个答案:

答案 0 :(得分:3)

所以有三个不相关的问题。您提供的报价中的第一个:

struct T * p;

这是非法的,因为T是一个typedef。

T{};

这在命名空间级别是非法的,但在其他概念中是合法的,例如作为全局初始化或函数内部的一部分:

T t = T{};
void f() { T{}; }

这实际上意味着创建一个类型为T值初始化临时对象。

T::T(){}

这是默认构造函数的有效定义,除了你没有声明一个。如果您修改S以使用户声明默认构造函数可以工作:

struct S { S(); };

为什么语言设计为不允许最后两行?

在更新的问题中,这两行是:

struct T* p;
T::T() {}

第二个是合法的,但是您正在尝试定义一个尚未声明为成员的函数,因此这也与原始文本无关。这给我们留下了一个:struct T* p

动机来自C.用户定义的类型和其他名称的标识符似乎位于不同的范围内,当查找尝试解析不符合structenum的名称时,它将忽略结构和枚举,在尝试解析structenum时忽略其他所有内容。以下是有效的C(和C ++):

struct T {};          // 1
typedef struct S {} T;  // 2
struct T t;

在C ++中,查找规则有所改变,你可以使用类型说明符而不明确限定它,但这是另一回事。此外,typedef-ed名称可以在C中无法使用的其他上下文中使用。

特殊情况是查找详细的类型说明符,如果typedef-ed名称可以在详细的类型说明符中使用吗?如果是,则上面程序的语义会发生变化,C t中的T类型(在1中定义),在C ++中它将变为S(在2中定义)

请注意,这在某种程度上是一个疯狂的猜测,我没有制定规则,我不知道那里考虑了什么。请注意,C和C ++在这方面从来没有真正兼容,类似的例子改变了C和C ++中的语义:

int T;
void f() {
   struct T { int data[10]; };
   printf("%d\n", sizeof(T));
}

该程序将在C ++中打印比C中大10倍的数字。但是使用类型而不必使用classstruct来限定它的能力可能比打破兼容性更重要。少数情况......