Irf*_*rfy 14 c++ move-constructor c++11
没有移动构造函数但带有接受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;
}
Run Code Online (Sandbox Code Playgroud)
T 将没有隐式移动构造函数,因为它具有用户定义的复制构造函数.
但是,如果我们取消注释移动构造函数的显式删除,则代码不再编译.为什么是这样?我原以为显式复制构造函数仍然会满足std::is_move_constructible.
重载是否起作用,选择声明的移动构造函数然后失败,因为它被删除了?
如果a no implicit move ctor和deleted move ctorclass 之间的移动构造性之间的差异是由标准规定的,请引用,并且如果可能的话,给出一个基本原理(例如"提供禁止移动构造的设施" - 首先想到的事情).
Lær*_*rne 17
这是对我的第一个答案的完整修改,纠正一些错误,并从标准中引用并引用提问者所希望的一些细节.
什么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 satis?ed if and only if the following variable de?nition would
be well-formed for some invented variable t:
T t(create<Args>()...);
Run Code Online (Sandbox Code Playgroud)
(......)
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-quali?ed) void,
or an array of unknown bound.
Run Code Online (Sandbox Code Playgroud)
创建移动构造函数时
标准说,只有当用户没有声明复制构造函数,移动构造函数,赋值运算符或析构函数时,才会创建默认移动构造函数.
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
Run Code Online (Sandbox Code Playgroud)
但是,该标准允许您使用类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-?eld),
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).
Run Code Online (Sandbox Code Playgroud)
因此,如果您有一个复制构造函数T::T(S& other)和一个y类型的对象T&&,即一个rvalue引用T,那么它y是与引用兼容的,T&并且T x(y)是一个有效的表达式来调用复制构造函数T::T(S&).
示例结构的作用
让我继续您的第一个示例,删除const关键字,以避免说明引用需要比初始化程序更多cv限定.
struct S {
S(S&) {}
};
Run Code Online (Sandbox Code Playgroud)
我们来检查条件.由于存在用户定义的复制构造函数,因此没有隐式默认的移动构造函数.但是,如果y是类型S,则std::move(y)类型S&&的引用与类型兼容S&.因此S x(std::move(y))完全有效并调用复制构造函数S::S(const S&).
第二个例子是做什么的
struct T {
T(T&) {}
T(T&&) = delete;
};
Run Code Online (Sandbox Code Playgroud)
同样,没有定义移动构造函数,因为存在用户定义的复制构造函数和用户定义的移动构造函数.再次让我们y的类型T和考虑T x(std::move(y)).
但是,这次多个构造函数可以适合表达式,因此执行过载选择.尝试只使用最专业的匹配构造函数,因此只T::T(T&&)尝试调用移动构造函数.但移动构造函数已删除,因此无效.
结论
第一个结构,S可以使用其复制构造函数来执行类似移动的表达式,因为它是此表达式的最专业的构造函数.
第二个结构T必须使用其显式声明的移动构造函数来执行类似移动的表达式,因为它是最专业的.但是,删除了该构造函数,move-construction表达式失败.
可移动构造类是具有隐式或用户声明的移动构造函数的类。或被称为右值引用的副本构造函数。除非类具有已删除的move构造函数,否则将引发这些构造函数。
所以:
struct T {
T(const T&) {}
};
Run Code Online (Sandbox Code Playgroud)
是可移动的可构造类,因此您可以从各自的特质中获得成功。
声明move构造函数delete:
struct T {
T(const T&) {}
T(T&&) = delete;
};
Run Code Online (Sandbox Code Playgroud)
使您的班级不可动摇。
即使move构造函数是delete,它也会像未删除一样参与重载解析。因此,作为直接匹配是优选的。
为了is_move_constructible提供成员常量valuetrue T obj(T&&);,如果删除的构造函数的格式不正确,则变量定义必须格式正确T。因此,您获得的价值等于假。
现在,关于在编译时如何发生这种情况。寻找魔法std::declval。std::declval在某处使用trait的实现来评估是否可以在不实际评估表达式的情况下移动类对象。
| 归档时间: |
|
| 查看次数: |
1794 次 |
| 最近记录: |