以下代码(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),该程序格式错误。 - 后注]
答案 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.用户定义的类型和其他名称的标识符似乎位于不同的范围内,当查找尝试解析不符合struct
或enum
的名称时,它将忽略结构和枚举,在尝试解析struct
或enum
时忽略其他所有内容。以下是有效的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倍的数字。但是使用类型而不必使用class
或struct
来限定它的能力可能比打破兼容性更重要。少数情况......