C++ 为什么C++;是否允许您移动包含已删除移动操作的对象的类?

C++ 为什么C++;是否允许您移动包含已删除移动操作的对象的类?,c++,c++11,c++14,language-lawyer,move-semantics,C++,C++11,C++14,Language Lawyer,Move Semantics,为什么允许我在包含具有删除移动语义类型的字段的类上使用std::move(案例1),但不允许在此类实例上使用它(案例2) 我理解案例2。我已经显式删除了move构造函数,因此如果我尝试移动它,就会出现错误。但我希望在案例1中也会出现这种情况,因为这样的类也在移动 class TestNonMovable { std::string ss; public: TestNonMovable(){} TestNonMovable(const TestNonMovable&) {}

为什么允许我在包含具有删除移动语义类型的字段的类上使用
std::move
(案例1),但不允许在此类实例上使用它(案例2)

我理解案例2。我已经显式删除了move构造函数,因此如果我尝试移动它,就会出现错误。但我希望在案例1中也会出现这种情况,因为这样的类也在移动

class TestNonMovable {
  std::string ss;
 public:
  TestNonMovable(){}
  TestNonMovable(const TestNonMovable&) {}
  TestNonMovable(TestNonMovable&&) = delete;
};

class SomeClass {
  TestNonMovable tnm;
};

int main() {    
    // case1: This compiles, my understanding is that for SomeClass::tnm compiler will use copy constrctor
    SomeClass sc1;
    SomeClass sc2 = std::move(sc1);

    // case2: This does not compile, move constructor is explicitly deleted, compiler will not try using copy constructor
    TestNonMovable tnm;
    TestNonMovable tnm2 = std::move(tnm); //error: use of deleted function 'TestNonMovable::TestNonMovable(TestNonMovable&&)'
}

请注意这两个类之间的差异。对于
TestNonMovable
(案例2),您可以显式地将移动构造函数声明为
delete
。使用
TestNonMovable tnm2=std::move(tnm)在重载解析中选择已删除的移动构造函数,然后导致错误

对于
SomeClass
(案例1),您没有显式声明move和copy构造函数。复制构造函数将被隐式声明和定义,但移动构造函数将被隐式声明和定义为删除,因为它有一个不可移动的数据成员注意,不会参与过载解决。使用
SomeClass sc2=std::move(sc1),选择复制构造函数,然后代码正常工作。从
std::move
返回的右值引用也可以绑定到const的左值引用(即
constsomeclass&

重载解析将忽略已删除的隐式声明的移动构造函数(否则将阻止从右值进行复制初始化)。(从C++14开始)


顺便说一句:在这两种情况下,它本身都是允许的。它不执行移动操作,只是将参数转换为右值。在这两种情况下,移动操作都是在构造时进行的。

您的引用中说“从C++14开始”,但问题被标记为C++11。答案是否适用于这两种情况?@CarstenS由于此更改是由a引入的,所以实现有权在C++11模式下应用此规则,而Clang和GCC都是这样做的。相关: