是否有理由在禁止使用抽象类型方面区分静态和非静态数据成员?

Is there a reason to differentiate between static and non-static data members in terms of prohibition of the usage of abstract types?

class.abstract中我们可以在注释3中看到:

An abstract class can be used only as a base class of some other class; no objects of an abstract class can be created except as subobjects of a class derived from it ([basic.def], [class.mem]).

这排除了抽象 类 作为子对象的用法,这对我来说很有意义(尽管这只是一个注释,IIRC 是非规范的)。

然而,在 class.mem 中我们可以读到:

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 5: 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]

(强调我的)

我觉得奇怪的是具体的措辞:“非静态”。为什么要明确说明this指的是非静态成员呢?我不相信我们可以有 static 抽象类型对象的声明或定义。该标准是否真的允许 static 数据成员是抽象的,而没有一个理智的编译器实现它?或者它确实禁止此类使用(在那种情况下,为什么在上述段落中区分静态数据和非静态数据)?

第一个引用中有您问题的答案

An abstract class can be used only as a base class of some other class; no objects of an abstract class can be created except as subobjects of a class derived from it ([basic.def], [class.mem]).

因此,由于静态数据成员是相对于声明它的 class 类型对象的独立对象,因此不能将其创建为抽象 class 的对象。另一方面,当我们谈到创建 class 类型的对象时,我们指的是它的非静态数据成员,它们是 class 类型对象的子对象。静态数据成员的实例化独立于声明它们的 class 对象的实例化。

Why is it explicitly stated that this refers to non-static members?

因为这允许声明具有不完整类型的静态成员。这是一个允许的最小示例,但如果该规则中未明确说明“非静态”则不允许:

struct S {
    // array of unknown bound is an incomplete type
    static int arr[];
    //int arr2[]; // is not allowed because of the rule
};

int S::arr[3]; // definition of the static member

Does the standard actually allow static data members to be abstract

不,这会与 unless there was a more specific rule overriding it (and there isn't to my knowledge). Specifying the rule to non-static seems to be relevant to incomplete types only; and not to abstract types. As such, listing "abstract type" in the rule explicitly seems redundant and thus confusing (but not contradictory) to me Edit: Brian's 引用的规则相矛盾,澄清为什么它有意义。

在定义 class 之前不知道 class 是否抽象。

一直允许声明具有不完整class类型的静态数据成员,只要该类型在静态数据成员时是完整的已定义。由于静态数据成员的类型在其 声明 上可能不完整,因此它也可能是编译器尚不知道的抽象 class 是抽象的。出于这个原因,将抽象性检查推迟到静态数据成员的定义是合适的。在定义时,如果发现静态数据成员的类型是抽象的 class、,那么 编译器应该发出诊断。这是 P0929 中的推理,它添加了 C++20 中的当前措辞。

对于非静态数据成员,声明时要求其类型完整,非静态数据成员的声明作为定义。所以此时必须检查抽象性。