在其自己的定义中使用不完整类型是否需要诊断?

Does using an incomplete type within its own definition require a diagnostic?

这是 this 问题的语言律师跟进,所有答案都同意以下内容 不允许

struct A { A a; };

有几种情况可以在类型定义本身中使用不完整的类型,例如

struct A { A *a; };
struct A { A &a; };
struct A { std::unique_ptr<A> a; };
struct A { std::vector<A> a; };     // since c++17

等等

我的问题是,是否需要编译器来诊断以不允许的方式使用不完整类型的程序?即它是病态的吗?或者这些程序有UB吗?或者别的什么?

我的感觉是,某些情况只是 UB,例如 vector 示例,编译器通常不会对其进行诊断,即使它仅在 c++17 中合法化。

为了澄清,我只是询问在类型本身的定义中使用不完整的类型,如所示示例。

这取决于确切的规则。必须诊断违反标准核心语言部分中与不完整 class 类型相关的大多数规则。除非另有说明,否则用作标准库模板的模板参数是未定义的行为,这为实现提供了更多的自由度。

这些规则需要诊断(因为它们用“应”声明):

[basic.def]/5:

In the definition of an object, the type of that object shall not be an incomplete type ([basic.types]), an abstract class type, or a (possibly multi-dimensional) array thereof.

[dcl.fct.def.general]/2:

The type of a parameter or the return type for a function definition shall not be a (possibly cv-qualified) class type that is incomplete or abstract within the function body unless the function is deleted ([dcl.fct.def.delete]).

[expr.ref]/4(关于.运算符前的操作数表达式的类型):

The class type shall be complete unless the class member access appears in the definition of that class. [ Note: If the class is incomplete, lookup in the complete class type is required to refer to the same declaration ([basic.scope.class]). — end note ]

由于 -> 运算符的内置含义定义为 A->B 等同于 (*A).B,这也适用于 -> 运算符表达式。

[class.mem]/15:

The type of a non-static data member shall not be an incomplete type ([basic.types]), an abstract class type ([class.abstract]), or a (possibly multi-dimensional) array thereof. [ Note: In particular, a class C cannot contain a non-static member of class C, but it can contain a pointer or reference to an object of class C. — end note ]

[class.derived]/2(关于 class 定义的基础 class 列表):

A class-or-decltype shall denote a (possibly cv-qualified) class type that is not an incompletely defined class ([class.mem]); any cv-qualifiers are ignored.

还有更多核心语言规则禁止不完整的 class 类型,但以上是最常见的相关规则。另请参阅 [basic.def.odr]/12.

中需要完整 class 的非规范上下文列表

如果 scope 命名不完整 [=60=,我没有看到 qualified-id scope::name 格式不正确] 类型,但在这种情况下名称查找肯定会失败,这是可诊断的违规行为。

对于标准库,对不完整类型作为模板参数的总体禁止是 [res.on.functions]/(2.5):

In certain cases (replacement functions, handler functions, operations on types used to instantiate standard library template components), the C++ standard library depends on components supplied by a C++ program. If these components do not meet their requirements, this document places no requirements on the implementation.

In particular, the effects are undefined in the following cases:

  • ...

  • If an incomplete type ([basic.types]) is used as a template argument when instantiating a template component or evaluating a concept, unless specifically allowed for that component.

如前所述,C++17 添加了实例化 class std::vector<T, Alloc> 的特定权限,但其成员的 none,如果 T 不完整且 Alloc满足“分配器完整性要求”([vector.overview]/4)