简单可复制的类 - C++20 中发生了什么变化?

Raz*_*ius 6 c++ c++20 trivially-copyable

标准说

一个普通可复制的类是一个类:

(1.1) 至少有一个合格的复制构造函数、移动构造函数、复制赋值运算符或移动赋值运算符([special]、[class.copy.ctor]、[class.copy.assign]),

(1.2) 其中每个合格的复制构造函数、移动构造函数、复制赋值运算符和移动赋值运算符都是微不足道的,并且

(1.3) 有一个简单的、未删除的析构函数 ([class.dtor])。

现在,我不完全确定这意味着什么。是否意味着拥有其中之一就足够了?例如,一个具有简单复制构造函数和复制赋值运算符以及显式删除的移动构造函数和移动赋值运算符的类是可以简单复制的,或者这意味着我有未删除的“big 6”并且它们中的每一个都是平凡的?

如果我从字面上理解这一点,那么只有一个构造函数或赋值运算符就足够了。根据cppreference在 c++20 之前就是这种情况。如果没有任何改变(即我仍然可以删除赋值运算符或构造函数),为什么措辞会改变?pre c++20 和 C++20 标准含义有什么区别?

更新

实验(例如Spencer 答案中的实验)表明我的猜测是正确的。我不明白的是 - 为什么要改变 C++20 标准中的措辞。实际上有什么改变吗?

c++17 定义的链接。

在 c++17 中,定义是:

  1. 一个普通可复制的类是一个类:

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

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

(6.3) 有一个简单的、未删除的析构函数。

旧定义和新定义之间是否存在细微差别?

Bar*_*rry 15

pre c++20 和 C++20 标准含义有什么区别?

对于 C++20 之前的课程,没有。对于 C++20 后的类,区别在于约束。

旧的措辞谈到特殊成员函数是“不可删除的”。新的措辞谈到他们“有资格”。合格在[special]/6中定义:

符合条件的特殊成员函数是指满足以下条件的特殊成员函数:

  • 该功能未删除,
  • 满足关联的约束([temp.constr])(如果有),并且
  • 没有同类的特殊成员函数受到更多限制([temp.constr.order])。

您可以将其视为 C++17 规则只有第一个项目符号,而 C++20 规则添加了接下来的两个项目符号(C++17 没有约束,因此后两个项目符号很容易满足)。原因可以在添加这个措辞的论文P0848(Conditionally Trivial Special Member Functions)(我的论文)中找到。

这样做的目标是做正确的事情,即可optional<int>平凡复制、optional<string>可复制但不可平凡复制、以及optional<unique_ptr<int>>不可复制:

template <class T>
struct optional {
    // #1
    optional(optional const&)
        requires copyable<T> && trivially_copyable<T>
        = default;

    // #2
    optional(optional const&) requires copyable<T>;
};
Run Code Online (Sandbox Code Playgroud)

在 P0848 之前, 和#1#2被视为 的复制构造函数optional<int>,并且因为#2不是平凡的,所以它无法满足每个复制构造函数都是平凡的要求。但这并不重要#2,因为它#1实际上是唯一重要的复制构造函数 - 并且新的 C++20 规则确保了这种情况。

具体来说,#2符合条件,因为#1受到更多限制,因此我们只关心#1确定是否optional<int>可以轻松复制。那个复制构造函数简单,所以我们没问题。另一方面,对于,不满足 的optional<string>关联约束(不是简单可复制的),因此合格的复制构造函数是,这并不简单。#1string#2