了解`std :: is_move_constructible` [英] Understanding `std::is_move_constructible`

查看:201
本文介绍了了解`std :: is_move_constructible`的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

Types without a move constructor, but with a copy constructor that accepts const T& arguments, satisfy std::is_move_constructible. For example, in the following code:

#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 没有隐式的move构造函数,因为它具有用户定义的副本构造函数。

T will have no implicit move constructor as it has a user-defined copy constructor.

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

However, if we uncomment the explicit delete of the move constructor, the code no longer compiles. Why is this? I would have expected that the explicit copy constructor would still satisfy std::is_move_constructible.

过载是否起着作用,选择声明的move构造函数,然后由于删除而失败了?

Does overload play a role, choosing the declared move constructor and then failing because it is deleted?

如果在没有隐式移动ctor 和标准要求的已删除移动ctor 类,请引用,并在可能的情况下提供理由(例如为禁止移动施工提供便利-首先想到的就是这一点。)

If this difference between move constructibility between a no implicit move ctor and a deleted move ctor class is mandated by the standard, please quote, and if possible, give a rationale (like "to provide a facility for forbidding move construction"—first thing that jumps to mind).

推荐答案

彻底修改了我的第一个答案,纠正了所说的一些错误,并引用了标准中的引号,并详细列出了发问者希望的一些细节。

This is a complete revamp of my first answer, to correct some mistakes said and to have quotes from the standard and to nail some details the questioner wishes.

$ c> std :: is_move_constructible 实际上可以

What std::is_move_constructible actually do

如果 T 是一个结构,然后 std :: is_move_constructible&T; 求值转到 std :: is_constructible< T,T&> 。如果 T x(y)是一个格式正确的表达式,则 std :: is_constructible< T,U> 有效一些 y 类型为 U 的人。因此,对于 std :: is_move_constructible< T> 为真, T x(std :: move(y))对于类型 T y ,必须格式正确。

If T is a structure then std::is_move_constructible<T> evaluates to std::is_constructible<T,T&&>. std::is_constructible<T,U> is valid if T x(y) is a well-formed expression for some y of type U. Thus for std::is_move_constructible<T> to be true, T x(std::move(y)) must be well-formed for y of type 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.

创建移动构造函数时

标准说,只有在用户未声明复制构造函数,移动构造函数,赋值运算符或析构函数的情况下,才创建默认的移动构造函数。

The standard says a default move constructor is created only when no copy constructor, move constructor, assignment operator or a destructor has been declared by the user.

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

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

However the standard allows you to initialize a class lvalue-reference with a class rvalue.

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 )和类型为 T&& 的对象 y ,即对 T ,则 y T& 具有参考兼容性 T x(y)是调用副本构造函数 T :: T(S&)的有效表达式。

Thus if you have a copy constructor T::T(S& other) and an object y of type T&&, i.e. a rvalue reference to T, then y is reference-compatible with T& and T x(y) is a valid expression to call the copy constructor T::T(S&).

示例结构的作用

让我来看第一个示例,删除 const 关键字,以避免说明引用需要比初始值设定者更具有cv资格十次。

Let me go with your first example, removing the const keywords, to avoid stating ten times that the reference needs to be more cv-qualified than the initializer.

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

让我们检查一下条件。由于存在用户定义的副本构造函数,因此没有隐式默认的move构造函数。但是,如果 y 的类型为 S ,则
,则 std :: move (y),类型为 S& ,与类型为 S& 。因此 S x(std :: move(y))完全有效,并调用副本构造函数 S :: S(const S&)

Let's check the condition. There is no implicitly defaulted move constructor since there is a user-defined copy constructor. However, if y is of type S, then std::move(y), of type S&&, is reference compatible with type S&. Thus S x(std::move(y)) is perfectly valid and call the copy constructor S::S(const S&).

第二个示例做什么

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

同样,没有定义移动构造函数,因为存在用户定义的副本构造函数用户定义的move构造函数。再次让 y 的类型为 T 并考虑 T x(std :: move(y ))

Again, no move constructor is defined as there is a user defined copy constructor and a user-defined move constructor. Again let y be of type T and consider T x(std::move(y)).

但是,这次可以在表达式中放入多个构造函数,因此将执行重载选择。仅尝试使用最专业的匹配构造函数,因此仅尝试调用move构造函数 T :: T(T&&)。但是move构造函数被删除,因此无效。

However, this time multiple constructor can fit in the expression, so an overload selection is performed. Only the most specialized matching constructor is attempted to work with so only the move constructor T::T(T&&) is attempted to call to. But the move constructor is deleted, so this is invalid.

结论

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

The first struct, S, can use its copy constructor usable to perform a move-like expression, as it is the most specialized constructor for this expression.

第二个结构 T 必须使用其显式声明的move构造函数来执行类似move的表达式,这也是因为它是最专门。但是,删除该构造函数后,move-construction表达式将失败。

The second struct, T, have to use its explicitly declared move constructor to perform the move-like expression, again because it is the most specialized. However that constructor is deleted, the move-construction expression fails.

这篇关于了解`std :: is_move_constructible`的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆