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

Why can a typedef-name for a struct not be used interchangeably with the struct name?

本文关键字:结构 互换 不能 typedef 为什么      更新时间:2023-10-16

以下代码(实际示例)不编译:

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名称来标识详细类型说明符(7.1.6.3)、类定义(第9条)、构造函数声明(12.1)或析构函数声明(12.4)的主题,则程序格式错误。--尾注]

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

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("%dn", sizeof(T));
}

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