c++ - 我如何误解有关“可简单复制”的 C++ 标准?
问题描述
下面代码中的静态断言失败。
当然,我知道这是因为 Bar 中用户提供了移动构造函数。
#include <type_traits>
using namespace std;
struct Bar
{
public:
Bar() = default;
Bar(const Bar&) = default;
~Bar() = default;
Bar(Bar&&)
{
}
};
struct Foo
{
Bar b;
Foo() = default;
~Foo() = default;
Foo(const Foo&) = default;
Foo(Foo&&) = delete;
Foo & operator= (Foo && ) = delete;
Foo & operator= (const Foo & ) = delete;
};
static_assert(is_trivially_copyable_v<Foo>); // Fails
我不明白的是如何解释有关琐碎可复制性的标准。从 C++ 17 标准:
一个可简单复制的类是一个类:
(6.1) 其中每个复制构造函数、移动构造函数、复制赋值运算符和移动赋值运算符([class.copy]、[over.ass])要么被删除,要么不重要,
(6.2) 具有至少一个未删除的复制构造函数、移动构造函数、复制赋值操作符或移动赋值操作符,并且
(6.3) 有一个微不足道的、未删除的析构函数。
在我看来, Foo 符合以下标准:
6.1:它们都被删除了,除了复制构造函数是微不足道的。Bar 也有一个平凡的复制构造函数,因此应该确保 Foo 复制构造函数是真正平凡的。
6.2:默认的拷贝构造函数
6.3: Foo 析构函数是默认的,Bar 也是默认析构函数,所以析构函数应该是微不足道的。
我没有得到什么?
顺便说一句,除了更好地理解标准之外,我实际上并没有尝试做任何事情。
解决方案
除了我在这里从根本上错过了一些东西,我认为目前在标准中没有关于这一点的实际模糊陈述,这实际上是我的观点非常直截了当,这意味着,你是对的。您的类 Foo 应该可以轻松复制。
从您的 Foo 类的顶层开始:
class6说:
一个可简单复制的类是一个类:
(6.1) 其中每个复制构造函数、移动构造函数、复制赋值运算符和移动赋值运算符([class.copy]、[over.ass])要么被删除,要么不重要,
(6.2) 具有至少一个未删除的复制构造函数、移动构造函数、复制赋值操作符或移动赋值操作符,并且
(6.3) 有一个微不足道的、未删除的析构函数。
第 2) 点和第 3) 点是微不足道的和应验的。
第1点):这里唯一相关的构造函数是复制构造函数。那么它是微不足道的吗?
11
类 X 的复制/移动构造函数如果不是用户提供的并且如果:
(11.1) 类 X 没有虚函数和虚基类,并且
(11.2) 选择复制/移动每个直接基类子对象的构造函数是微不足道的,并且
(11.3) 对于 X 的每个类类型(或其数组)的非静态数据成员,选择复制/移动该成员的构造函数是微不足道的;
否则复制/移动构造函数是不平凡的。
同样,第 1) 点和第 2) 点是微不足道的和应验的。对于第 3 点,该标准使用了“复制/移动”的终点,而不是复制和移动,在这里强调了双重区分正交(!)性质(草案中的常见和直接方案)。由于 Bar 有一个微不足道的未删除复制构造函数,因此严格阅读标准不会有任何麻烦,因为 bar 成员的选定复制构造函数应该如何成为用户定义的移动构造函数(请参阅默认的成员复制复制构造函数)?如果无法找到可选的移动构造函数,则复制构造方式的“衰减”是合理的,但这里不是这种情况。
推荐阅读
- angular - 如何自定义验证 FormArray
- java - 用 JNA 映射 c++ 函数
- .net - 使用 .NET Core 3.1 构建需要更多时间和内存(.NET Core 主机和 Visual Studio 代码)
- gradle - Gradle ShadowJar:包含递归依赖
- c++ - std::map 如何计算重复项
- node.js - 如何发送 zip 文件夹作为来自 nodejs 服务器的响应
- c++ - 启动时 MSYS2 分段错误的 GTK3
- wpf - 动态占位符 WPF 动画
- php - 如何将每列中的 2 个值输入到另一个表中的一列
- java - Spring Boot - 特定 URL AccessDecisionVoter