为什么 is_trivially_copyable_v 在 GCC 和 MSVC 中不同?
Why is is_trivially_copyable_v different in GCC and MSVC?
当 运行 这个简单的程序时,观察到不同的行为取决于编译器。
它在 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>
被定义为真]:
Arithmetic types (6.8.2), enumeration types, pointer types, pointer-to-member types (6.8.3), std::nullptr_t,
and cv-qualified (6.8.4) versions of these types are collectively called scalar types. Scalar types, trivially
copyable class types (11.2), arrays of such types, and cv-qualified versions of these types are collectively called
trivially copyable types.
其中 trivially copyable class types
定义为 11.2/1 [class.prop]:
1 A trivially copyable class is a class:
— that has at least one eligible copy constructor, move constructor, copy assignment operator, or move assignment operator (11.4.4, 11.4.5.3, 11.4.6),
— where each eligible copy constructor, move constructor, copy assignment operator, and move assignment operator is trivial, and
— that has a trivial, non-deleted destructor (11.4.7).
符合条件(11.4.4 [特殊]):
1 Default constructors (11.4.5.2), copy constructors, move constructors (11.4.5.3), copy assignment operators,
move assignment operators (11.4.6), and prospective destructors (11.4.7) are special member functions.
6 An eligible special member function is a special member function for which:
— the function is not deleted,
— the associated constraints (13.5), if any, are satisfied, and
— no special member function of the same kind is more constrained
trivial
用于这些函数(如 11.4.5.3/11 [class.copy.ctor]、11.4.6/9 [class.copy.assign]、11.4.7/8 [class.dtor]) 一般表示:
- the function is not user-provided.
- there's nothing virtual to the class
- each non-static data member has the relevant trivial function
根据 9.5.2/5 [dcl.fct.def.default],提供的程序中删除的函数不是用户提供的:
... A function is user-provided if it is user-declared
and not explicitly defaulted or deleted on its first declaration. ...
如果我的理解是正确的,struct S
有 deleted
special member functions
使它们成为非 eligible
,这不符合 trivially copyable class type
的要求] 和 trivially copyable type
。因此,符合行为是 MSVC 的。这是正确的吗?
GCC 和 Clang 报告说 S
is trivially copyable in C++11 through C++23 standard modes. MSVC reports that S
is not trivially copyable 在 C++14 到 C++20 标准模式中。
N3337 (~ C++11) and N4140 (~ C++14) 说:
A trivially copyable class is a class that:
- has no non-trivial copy constructors,
- has no non-trivial move constructors,
- has no non-trivial copy assignment operators,
- has no non-trivial move assignment operators, and
- has a trivial destructor.
根据这个定义,S
是可简单复制的。
N4659 (~ C++17) 说:
A trivially copyable class is a class:
- where each copy constructor, move constructor, copy assignment operator, and move assignment
operator is either deleted or trivial,
- that has at least one non-deleted copy constructor, move constructor, copy assignment operator, or
move assignment operator, and
- that has a trivial, non-deleted destructor
根据这个定义,S
不是可简单复制的。
N4860 (~ C++20) 说:
A trivially copyable class is a class:
- that has at least one eligible copy constructor, move constructor, copy assignment operator, or move
assignment operator,
- where each eligible copy constructor, move constructor, copy assignment operator, and move assignment
operator is trivial, and
- that has a trivial, non-deleted destructor.
根据这个定义,S
不是可简单复制的。
因此,正如发布的那样,S
在 C++11 和 C++14 中是可复制的,但在 C++17 和 C++20 中不是。
2016 年 2 月 DR 1734 采纳了更改。实施者通常将 DR 视为按照惯例适用于所有先前的语言标准。因此,根据 C++11 和 C++14 的已发布标准,S
是可平凡复制的,并且按照惯例,较新的编译器版本可能会选择将 S
视为 C++ 中不可平凡复制的11 和 C++14 模式。因此,可以说所有编译器都适用于 C++11 和 C++14。
对于 C++17 及更高版本,S
显然不可简单复制,因此 GCC 和 Clang 是不正确的。这是GCC bug #96288 and LLVM bug #39050
当 运行 这个简单的程序时,观察到不同的行为取决于编译器。
它在 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>
被定义为真]:
Arithmetic types (6.8.2), enumeration types, pointer types, pointer-to-member types (6.8.3), std::nullptr_t, and cv-qualified (6.8.4) versions of these types are collectively called scalar types. Scalar types, trivially copyable class types (11.2), arrays of such types, and cv-qualified versions of these types are collectively called trivially copyable types.
其中 trivially copyable class types
定义为 11.2/1 [class.prop]:
1 A trivially copyable class is a class:
— that has at least one eligible copy constructor, move constructor, copy assignment operator, or move assignment operator (11.4.4, 11.4.5.3, 11.4.6),
— where each eligible copy constructor, move constructor, copy assignment operator, and move assignment operator is trivial, and
— that has a trivial, non-deleted destructor (11.4.7).
符合条件(11.4.4 [特殊]):
1 Default constructors (11.4.5.2), copy constructors, move constructors (11.4.5.3), copy assignment operators, move assignment operators (11.4.6), and prospective destructors (11.4.7) are special member functions.
6 An eligible special member function is a special member function for which:
— the function is not deleted,
— the associated constraints (13.5), if any, are satisfied, and
— no special member function of the same kind is more constrained
trivial
用于这些函数(如 11.4.5.3/11 [class.copy.ctor]、11.4.6/9 [class.copy.assign]、11.4.7/8 [class.dtor]) 一般表示:
- the function is not user-provided.
- there's nothing virtual to the class
- each non-static data member has the relevant trivial function
根据 9.5.2/5 [dcl.fct.def.default],提供的程序中删除的函数不是用户提供的:
... A function is user-provided if it is user-declared and not explicitly defaulted or deleted on its first declaration. ...
如果我的理解是正确的,struct S
有 deleted
special member functions
使它们成为非 eligible
,这不符合 trivially copyable class type
的要求] 和 trivially copyable type
。因此,符合行为是 MSVC 的。这是正确的吗?
GCC 和 Clang 报告说 S
is trivially copyable in C++11 through C++23 standard modes. MSVC reports that S
is not trivially copyable 在 C++14 到 C++20 标准模式中。
N3337 (~ C++11) and N4140 (~ C++14) 说:
A trivially copyable class is a class that:
- has no non-trivial copy constructors,
- has no non-trivial move constructors,
- has no non-trivial copy assignment operators,
- has no non-trivial move assignment operators, and
- has a trivial destructor.
根据这个定义,S
是可简单复制的。
N4659 (~ C++17) 说:
A trivially copyable class is a class:
- where each copy constructor, move constructor, copy assignment operator, and move assignment operator is either deleted or trivial,
- that has at least one non-deleted copy constructor, move constructor, copy assignment operator, or move assignment operator, and
- that has a trivial, non-deleted destructor
根据这个定义,S
不是可简单复制的。
N4860 (~ C++20) 说:
A trivially copyable class is a class:
- that has at least one eligible copy constructor, move constructor, copy assignment operator, or move assignment operator,
- where each eligible copy constructor, move constructor, copy assignment operator, and move assignment operator is trivial, and
- that has a trivial, non-deleted destructor.
根据这个定义,S
不是可简单复制的。
因此,正如发布的那样,S
在 C++11 和 C++14 中是可复制的,但在 C++17 和 C++20 中不是。
2016 年 2 月 DR 1734 采纳了更改。实施者通常将 DR 视为按照惯例适用于所有先前的语言标准。因此,根据 C++11 和 C++14 的已发布标准,S
是可平凡复制的,并且按照惯例,较新的编译器版本可能会选择将 S
视为 C++ 中不可平凡复制的11 和 C++14 模式。因此,可以说所有编译器都适用于 C++11 和 C++14。
对于 C++17 及更高版本,S
显然不可简单复制,因此 GCC 和 Clang 是不正确的。这是GCC bug #96288 and LLVM bug #39050