gpt4 book ai didi

c++ - 了解 `std::is_move_constructible`

转载 作者:IT老高 更新时间:2023-10-28 22:36:44 25 4
gpt4 key购买 nike

没有移动构造函数但具有接受 const T& 参数的复制构造函数的类型,满足 std::is_move_constructible。例如,在以下代码中:

#include <type_traits>

struct T {
T(const T&) {}
//T(T&&) = delete;
};

int main() {
static_assert(std::is_move_constructible<T>::value, "not move constructible");
return 0;
}

T 将没有隐式移动构造函数,因为它有一个用户定义的复制构造函数。

但是,如果我们取消注释移动构造函数的显式删除,代码将不再编译。为什么是这样?我本来希望显式复制构造函数仍然满足 std::is_move_constructible

重载是否起作用,选择声明的移动构造函数然后因为它被删除而失败?


如果标准规定了 no implicit move ctordeleted move ctor 类之间的移动构造性之间的差异,请引用,如果可能,请给出基本原理(例如“提供一种禁止移动施工的设施”——首先想到的就是)。

最佳答案

这是对我的第一个答案的全面修改,以纠正所说的一些错误并引用标准并指出提问者希望的一些细节。

什么std::is_move_constructible实际做

如果 T是一个结构然后std::is_move_constructible<T>计算结果为 std::is_constructible<T,T&&> . std::is_constructible<T,U>如果 T x(y) 则有效是一些 y 的格式良好的表达式类型 U .因此对于 std::is_move_constructible<T>说真的,T x(std::move(y)) y 的格式必须正确类型 T .

引用标准:

The predicate condition for a template specialization is_constructible<T, Args...>
shall be satisfied if and only if the following variable definition would
be well-formed for some invented variable t:
T t(create<Args>()...);

(...)

Template: template <class T> struct is_move_constructible;
Condition: For a referenceable type T, the same result as is_constructible<T, T&&>::value,
otherwise false.
Precondition: T shall be a complete type, (possibly cv-qualified) void,
or an array of unknown bound.

创建移动构造函数时

标准规定,仅当用户未声明复制构造函数、移动构造函数、赋值运算符或析构函数时,才会创建默认移动构造函数。

If the definition of a class X does not explicitly declare a move
constructor, one will be implicitly declared as defaulted if and only if
—X does not have a user-declared copy constructor,
—X does not have a user-declared copy assignment operator,
—X does not have a user-declared move assignment operator, and
—X does not have a user-declared destructor

但是,该标准允许您使用类右值初始化类左值引用。

Otherwise, the reference shall be an lvalue reference to a non-volatile const type
(i.e., cv1 shall be const), or the reference shall be an rvalue reference.
—If the initializer expression is an xvalue (but not a bit-field),
class prvalue, array prvalue or function lvalue and “cv1 T1”
is reference-compatible with “cv2 T2”, or (...)
then the reference is bound to the value of the initializer expression (...)
(or, in either case, to an appropriate base class subobject).

因此,如果你有一个复制构造函数 T::T(S& other)和一个对象 y类型 T&& ,即对 T 的右值引用,然后 yT& 引用兼容和 T x(y)是调用复制构造函数的有效表达式 T::T(S&) .

示例结构的作用

让我以您的第一个示例为例,删除 const关键字,以避免十次声明引用需要比初始值设定项更具 cv 限定。

struct S {
S(S&) {}
};

让我们检查一下情况。由于存在用户定义的复制构造函数,因此没有隐式默认的移动构造函数。然而,如果 yS 类型,然后 std::move(y) , 类型为 S&& , 与类型 S& 的引用兼容.因此S x(std::move(y))完全有效并调用复制构造函数S::S(const S&) .

第二个例子做了什么

struct T {
T(T&) {}
T(T&&) = delete;
};

同样,没有定义移动构造函数,因为有一个用户定义的复制构造函数一个用户定义的移动构造函数。再次让 y类型为 T并考虑T x(std::move(y)) .

但是,这一次表达式中可以容纳多个构造函数,因此执行了重载选择。仅尝试使用最专业的匹配构造函数,因此只有移动构造函数 T::T(T&&)试图调用。但是move构造函数被删除了,所以这是无效的。

结论

第一个结构,S , 可以使用它的复制构造函数来执行类似移动的表达式,因为它是这个表达式最专业的构造函数。

第二个结构,T ,必须使用其显式声明的移动构造函数来执行类似移动的表达式,因为它是最专业的。然而,该构造函数被删除,移动构造表达式失败。

关于c++ - 了解 `std::is_move_constructible`,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33939644/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com