以下所有标准引用均引用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. [...]
让我们将普通的类要求表示如下:
如下所示,
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/