首页 > 解决方案 > 我如何误解有关“可简单复制”的 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 也是默认析构函数,所以析构函数应该是微不足道的。

我没有得到什么?

顺便说一句,除了更好地理解标准之外,我实际上并没有尝试做任何事情。

标签: c++language-lawyer

解决方案


除了我在这里从根本上错过了一些东西,我认为目前在标准中没有关于这一点的实际模糊陈述,这实际上是我的观点非常直截了当,这意味着,你是对的。您的类 Foo 应该可以轻松复制。

从您的 Foo 类的顶层开始:

class6说:

一个可简单复制的类是一个类:

(6.1) 其中每个复制构造函数、移动构造函数、复制赋值运算符和移动赋值运算符([class.copy]、[over.ass])要么被删除,要么不重要,

(6.2) 具有至少一个未删除的复制构造函数、移动构造函数、复制赋值操作符或移动赋值操作符,并且

(6.3) 有一个微不足道的、未删除的析构函数。

第 2) 点和第 3) 点是微不足道的和应验的。

第1点):这里唯一相关的构造函数是复制构造函数。那么它是微不足道的吗?

class.copy#ctor-11回答:

11

类 X 的复制/移动构造函数如果不是用户提供的并且如果:

(11.1) 类 X 没有虚函数和虚基类,并且

(11.2) 选择复制/移动每个直接基类子对象的构造函数是微不足道的,并且

(11.3) 对于 X 的每个类类型(或其数组)的非静态数据成员,选择复制/移动该成员的构造函数是微不足道的;

否则复制/移动构造函数是不平凡的。

同样,第 1) 点和第 2) 点是微不足道的和应验的。对于第 3 点,该标准使用了“复制/移动”的终点,而不是复制和移动,在这里强调了双重区分正交(!)性质(草案中的常见和直接方案)。由于 Bar 有一个微不足道的未删除复制构造函数,因此严格阅读标准不会有任何麻烦,因为 bar 成员的选定复制构造函数应该如何成为用户定义的移动构造函数(请参阅默认的成员复制复制构造函数)?如果无法找到可选的移动构造函数,则复制构造方式的“衰减”是合理的,但这里不是这种情况。


推荐阅读