运行这个简单的程序时,根据编译器的不同会观察到不同的行为。
使用GCC 11.2编译时,它会打印true
,而使用MSVC 19.29.30137编译时会打印false
(两者都是截至今天最新版本)。
#include <type_traits>
#include <iostream>
struct S {
int a;
S() = delete;
S(S const &) = delete;
S(S &&) = delete;
S &operator=(S const &) = delete;
S &operator=(S &&) = delete;
~S() = delete;
};
int main() {
std::cout << std::boolalpha;
std::cout << std::is_trivially_copyable_v<S>;
}
相关引用(来自最新的C++23工作草案N4901):
根据20.15.5.4 [meta.unary.prop],如果T是在6.8.1/9 [basic.types.general]中定义的trivially copyable type
,则std::is_trivially_copyable_v<T>
被定义为true:
算术类型(6.8.2),枚举类型,指针类型,成员指针类型(6.8.3),std::nullptr_t和这些类型的cv限定版本被统称为标量类型。标量类型,trivially copyable类类型(11.2),这些类型的数组以及这些类型的cv限定版本被统称为trivially copyable类型。
其中trivially copyable类类型
在11.2/1 [class.prop]中定义:
1 一个trivially copyable类是一个类:
— 至少有一个合格的复制构造函数、移动构造函数、复制赋值运算符或移动赋值运算符(11.4.4, 11.4.5.3, 11.4.6),
— 每个合格的复制构造函数、移动构造函数、复制赋值运算符和移动赋值运算符都是trivial的,且
— 有一个trivial的、未删除的析构函数(11.4.7)。
合格的(11.4.4 [special]):
1 默认构造函数(11.4.5.2),复制构造函数,移动构造函数(11.4.5.3),复制赋值运算符,移动赋值运算符(11.4.6)和潜在析构函数(11.4.7)都是特殊成员函数。
6 合格的特殊成员函数是指满足以下条件的特殊成员函数:
— 函数没有被删除,
— 如果有的话,与之相关的约束(13.5)被满足,且
— 同类的特殊成员函数没有更多的约束。
这些函数的trivial
(如11.4.5.3/11 [class.copy.ctor],11.4.6/9 [class.copy.assign],11.4.7/8 [class.dtor]中所定义)通常意味着:
根据9.5.2/5 [dcl.fct.def.default],所提供程序中的删除函数不是用户提供的:
- 该函数不是用户提供的。
- 类中没有虚函数。
- 每个非静态数据成员都有相关的trivial函数。
“……如果一个函数是用户声明的并且在其第一次声明中没有明确地默认或删除,则该函数是用户提供的……”
如果我的理解正确,
struct S
有 deleted
special member functions
,使它们不符合 trivially copyable class type
和 trivially copyable type
的要求。因此,符合要求的行为是 MSVC 的。这样说对吗?
S
视为C++17及更高版本中的平凡可复制类型,但在C++14及以下版本中不是。 - Brian61354270