为什么CopyConstructible类型也必须是MoveConstructible类型?

时间:2019-02-06 11:24:36

标签: c++ c++-concepts c++20

cppreference中所述,类型 T 必须为 CopyConstructible 的要求是它也必须为 MoveConstructible 。 / p>

STL CopyConstructible概念的草案包含:

template <class T>
concept CopyConstructible =
   std::MoveConstructible<T> &&
   std::Constructible<T, T&> && std::ConvertibleTo<T&, T> &&
   std::Constructible<T, const T&> && std::ConvertibleTo<const T&, T> &&
   std::Constructible<T, const T> && std::ConvertibleTo<const T, T>;

支持命名的需求语句。给定上面的定义,像这样的类型:

struct HaveCopy {
   HaveCopy(const HaveCopy&)  = default;
   HaveCopy(HaveCopy&&)       = delete;
   HaveCopy& operator= (const HaveCopy&)  = default;
   HaveCopy& operator= (HaveCopy&&)       = delete;
};

无法通过简单的测试:

static_assert(std::CopyConstructible<HaveCopy>);

它已经过去了:

static_assert(std::is_copy_constructible<HaveCopy>::value);

因此,问题是为什么?标准委员会对此有何打算? HaveCopy不能移动构造,但在我看来几乎可以复制构造,std::is_copy_constructible<>同意我的看法。

Copyable概念也继承了相同的行为,即:

template <class T>
concept Copyable =
   std::CopyConstructible<T> &&
   std::Movable<T> &&
   std::Assignable<T&, const T&>;

所以测试:

static_assert(std::Copyable<HaveCopy>);

也会失败。这次故障增加了一倍。 CopyConstrucible<>Movable<>都不同意HaveCopy是可复制的。

讨论here在某种程度上相似,但是没有回答为什么。为什么我们需要这种行为?这种检查是否排除有效的副本可构造类型,或者HaveCopy根本不是副本可构造类型?如果是真的,最后一个似乎对我来说很奇怪。

有什么想法吗?

1 个答案:

答案 0 :(得分:7)

是的,CopyConstructible的概念与类型特征std::is_copy_constructible完全不同。您将重点放在move构造函数上,但是还有许多其他情况需要考虑。您认为这种类型应该是CopyConstructible吗?

struct A {
    A(A&) = delete;
    A(A const&);
};

这个怎么样?

struct B {
    explicit B(B const&);
};

要点是,您可以编写各种构造函数组合。这并不意味着它们都有意义或值得支持。具有复制构造函数但删除了move构造函数的类型根本没有意义。

概念不仅涉及语法检查,还涉及强制语义要求以推送有意义的类型-最终使编码变得更容易。如果仅检查is_copy_constructible,您要做的就是从const lvalue显式构造 。即使T x = y;y,写const T也已经超出了范围!从字面上看,这可能是可构造副本的含义,但是它比更广泛的“我可以从T来构造T”的意义要小得多-这与我们实际想到的内容非常接近考虑复制。这就是CopyConstructible这个概念给我们的。

当您浏览库时,还有其他一些概念(在语法上和语义上)需要比其名称的直接翻译所暗示的更多的内容。 EqualityComparableWith<T,U>不仅检查我可以写t == u,而且还检查u == tt != uu != tStrictTotallyOrdered不仅检查订购运算符,还 检查==。具有凝聚力的整体很重要。