c++ - 由于存在默认成员初始化程序,因此类类型很简单

标签 c++ c++17 language-lawyer

以下所有标准引用均引用N4659: March 2017 post-Kona working draft/C++17 DIS

可以预料的是,对非静态数据成员使用默认成员初始化器会使类变得不平凡:

// Well-formed according to both GCC and Clang (-std=c++17).
#include <type_traits>

struct Trivial { int a; int b; };
struct NotTrivial { int a; int b{0}; };

static_assert(std::is_trivial_v<Trivial>, "");
static_assert(!std::is_trivial_v<NotTrivial>, "");

int main() {}
(C++ 17)标准的哪些段落规定NotTrivial是一个非平凡的类?

最佳答案

以下所有标准引用均引用N4659: March 2017 post-Kona working draft/C++17 DIS

[class]/6控制什么是琐碎的类[摘录]:

[...] A trivial class is a class that is trivially copyable and has one or more default constructors, all of which are either trivial or deleted and at least one of which is not deleted. [...]


让我们将普通的类要求表示如下:
  • (A)该类是可微复制的,并且
  • (B)该类的所有默认构造函数都是平凡的或已删除,并且
  • (C)该类具有至少一个未删除的默认构造函数。

  • 如下所示,NonTrivial满足(A)(C)要求,但不满足(B)要求,因此并不琐碎。

    要求(A):少量可复制[已实现]
    要求(A)[class]/6约束:

    A trivially copyable class is a class:

    • (6.1) where each copy constructor, move constructor, copy assignment operator, and move assignment operator ([class.copy], [over.ass]) is either deleted or trivial,
    • (6.2) that has at least one non-deleted copy constructor, move constructor, copy assignment operator, or move assignment operator, and
    • (6.3) that has a trivial, non-deleted destructor.

    其中涉及构造函数和赋值运算符琐碎性的第一个子需求(6.1)分别由[class.copy.ctor]/11[class.copy.assign]/9控制:

    [class.copy.ctor]/11

    A copy/move constructor for class X is trivial if it is not user-provided and if:

    • (11.1) class X has no virtual functions and no virtual base classes, and
    • (11.2) the constructor selected to copy/move each direct base class subobject is trivial, and
    • (11.3) for each non-static data member of X that is of class type (or array thereof), the constructor selected to copy/move that member is trivial;

    otherwise the copy/move constructor is non-trivial.

    [class.copy.assign]/9

    A copy/move assignment operator for class X is trivial if it is not user-provided and if:

    • (9.1) class X has no virtual functions and no virtual base classes, and
    • (9.2) the assignment operator selected to copy/move each direct base class subobject is trivial, and
    • (9.3) for each non-static data member of X that is of class type (or array thereof), the assignment operator selected to copy/move that member is trivial;

    otherwise the copy/move assignment operator is non-trivial.


    所有这些都由NonTrivial完成。
    第二个子需求(6.2)涉及构造函数和赋值运算符的存在,仅限于隐式声明的特殊函数(如本例所示),分别由[class.copy.ctor]/6[class.copy.assign]/2控制:

    [class.copy.ctor]/6

    If the class definition does not explicitly declare a copy constructor, a non-explicit one is declared implicitly. If the class definition declares a move constructor or move assignment operator, the implicitly declared copy constructor is defined as deleted; otherwise, it is defined as defaulted. [...]

    [class.copy.assign]/2

    If the class definition does not explicitly declare a copy assignment operator, one is declared implicitly. If the class definition declares a move constructor or move assignment operator, the implicitly declared copy assignment operator is defined as deleted; otherwise, it is defined as defaulted. [...]


    因此,将为NonTrivial隐式声明一个复制构造函数和一个复制赋值运算符。从[class.copy.ctor]/8[class.copy.assign]/4 4可以得出,分别对于move构造函数和move赋值运算符也是如此。因此,NonTrivial满足子要求(6.2)。
    第三个子需求(6.3)由[class.dtor]/6控制:

    A destructor is trivial if it is not user-provided and if:

    • (6.1) the destructor is not virtual,
    • (6.2) all of the direct base classes of its class have trivial destructors, and
    • (6.3) for all of the non-static data members of its class that are of class type (or array thereof), each such class has a trivial destructor.

    Otherwise, the destructor is non-trivial.


    这由NonTrivial满足,因此(A)NonTrivial成立。

    要求(B):琐碎或已删除的默认构造函数[未实现]
    按照[class.ctor]/4 [extract]的规定:

    [...] If there is no user-declared constructor for class X, a non-explicit constructor having no parameters is implicitly declared as defaulted ([dcl.fct.def]).


    将为NonTrivial类隐式声明一个默认构造函数。但是,按照[class.ctor]/6,尤其是[class.ctor]/6.2的规定,此隐式声明的默认构造函数不是琐碎的:

    A default constructor is trivial if it is not user-provided and if:

    • [...]
    • (6.2) no non-static data member of its class has a default member initializer ([class.mem]), and [...]

    因此,NonTrivial类不满足(B)要求,因此并不简单。
    我们可能会注意到,[class.ctor] /6.2子句源自非静态数据成员初始化器N2628的原始提议,该提议提议添加

    no non-static data member of its class has an assignment-initializer, and


    作为[class.ctor]的附加琐碎要求。

    要求(C):存在默认构造函数[已实现]
    为了完整起见,我们可能注意到NonTrivial类满足[class.ctor]/4的要求(C)(在上一节中引用)。

    关于c++ - 由于存在默认成员初始化程序,因此类类型很简单,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63484416/

    相关文章:

    c++ - C++ 不是强制要求 (cond ? string_1 : string_2) initialize a string?

    c++ - 删除 vector 中的指针时出现段错误

    c++ - 结构化绑定(bind)和转发引用混合得好吗?

    c++ - 是否有提议将 std::bin 添加到 c++ 标准?

    c++ - [basic.execution] p5 句子 2 的意图

    c++ - C++中调用错误模板函数原型(prototype)问题

    c++ - 查找范围 [a, b] 中不在给定 std::set S 中的所有数字

    c++ - 从从左到右读取的所有类型创建嵌套包

    c++ - 从 `if constexpr` 分支扩展对象生命周期/范围

    C++ 标准 : is there a result object?