【发布时间】:2019-02-06 11:24:35
【问题描述】:
如cppreference 中所述,T 类型必须是CopyConstructible 的要求是它也是MoveConstructible。
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 根本不能复制构造?如果是真的,最后一个对我来说真的很奇怪。
有什么想法吗?
【问题讨论】:
-
Jonathan Wakely 在链接线程中的回答是否也回答了为什么部分? “MoveConstructible 不需要移动任何东西,只有从右值构造是可能的,并且所有 CopyConstructible 类型都可以从右值构造(即使它们可能执行深层复制而不是移动)。”
-
我的理解是,当某些东西被移动时,你不应该关心它实际上是被移动还是被复制,因此如果某物是
CopyConstructible,它自动是MoveConstructible,你无法区分,这并不是真正的额外要求 -
我同意 lubr,并将此问题标记为重复,您认为链接的答案没有回答什么部分?
-
虽然我很可能不太了解它...... Wakely 的回答说“我们试图避免反常类型 [和/所以],我们还需要移动构造函数,因为有人可能会使用要复制吗?”。为什么我们通过询问 MoveConstructible 概念来做到这一点?为什么在这样做时我们将 HaveCopy 排除在 CopyConstructible 之外?
-
这就像在问“为什么所有能被 4 整除的数字都必须能被 2 整除?”。由于
T &&到const T &的“隐式转换”,任何可以从const T &实例化的T都可以从T &&实例化。 “可以从T &&实例化”是 MoveConstructible 的定义方式
标签: c++ c++-concepts c++20