jot*_*tik 3 c++ language-lawyer compiler-bug move-semantics c++11
据我所知[class.copy.ctor]和[class.copy.assign],A
以下代码中的struct 不应该是可移动构造的,也不应该是move-assignable:
#include <type_traits>
struct X {
X() noexcept; // user-declared default constructor
~X() noexcept; // Force X not to be trivially copyable
X(X &&) = delete; // Explicitly deleted move constructor
X(X const &) = delete; // Explicitly deleted copy constructor
X & operator=(X &&) = delete; // Explicitly deleted move assignment operator
X & operator=(X const &) = delete; // Explicitly deleted copy assignment op.
};
static_assert(!std::is_copy_constructible<X>::value, "");
static_assert(!std::is_copy_assignable<X>::value, "");
static_assert(!std::is_move_assignable<X>::value, "");
static_assert(!std::is_move_constructible<X>::value, "");
static_assert(!std::is_trivially_copyable<X>::value, "");
static_assert(!std::is_trivially_copy_assignable<X>::value, "");
static_assert(!std::is_trivially_copy_constructible<X>::value, "");
static_assert(!std::is_trivially_move_assignable<X>::value, "");
static_assert(!std::is_trivially_move_constructible<X>::value, "");
struct A {
A() noexcept; // user-declared default constructor
A(A const &) noexcept; // user-declared copy constructor
A & operator=(A const &) noexcept; // user-declared copy assignment operator
X x;
};
static_assert(std::is_copy_constructible<A>::value, "");
static_assert(std::is_copy_assignable<A>::value, "");
static_assert(!std::is_move_assignable<A>::value, ""); // FAILS?!
static_assert(!std::is_move_constructible<A>::value, ""); // FAILS?!
static_assert(!std::is_trivially_copyable<A>::value, "");
static_assert(!std::is_trivially_copy_assignable<A>::value, "");
static_assert(!std::is_trivially_copy_constructible<A>::value, "");
static_assert(!std::is_trivially_move_assignable<A>::value, "");
static_assert(!std::is_trivially_move_constructible<A>::value, "");
Run Code Online (Sandbox Code Playgroud)
然而,两个静态断言都失败了GCC和Clang,这意味着由于某种原因A
,移动可分配和移动可构造.
在我的推理中,这不应该是,因为struct A
:
x
类型的字段,X
不能用任何其他类型直接初始化A::x
,因为所有构造函数X
都将参与重载决策,这是明确删除的.这是编译器错误还是我误解了什么?
它们是预期的行为,因为复制构造函数和复制赋值运算符的存在满足MoveConstructible的要求
类不必实现移动构造函数来满足此类型要求:采用const T&argument的复制构造函数可以绑定rvalue表达式.
该类型不必实现移动赋值运算符以满足此类型要求:通过值或作为const Type&获取其参数的复制赋值运算符将绑定到rvalue参数.
注意,std :: is_move_constructible和std :: is_move_assignable只是检查可以从rvalue参数构造/赋值的指定类型的对象.即使没有移动构造函数/赋值运算符,复制构造函数/赋值运算符也可以完成工作,因为rvalue参数也可以传递给const的左值引用.
编辑
注意您显示的示例代码移动构造函数/赋值运算符根本没有被声明(因为存在用户声明的复制构造函数和复制赋值运算符),所以它们不会影响重载解析和复制构造函数的结果/ assignment运算符将被调用.但是,如果你明确声明他们作为delete
,行为可能会改变,因为显式删除功能参与到重载决议,他们将被优先选择,然后std::is_move_constructible
和std::is_move_assignable
返回false
.