Why am I allowed to use std::move
on a class which contains fields of a type with deleted move semantics (case 1), but am not allowed to use it on an instance of such a class (case 2)?
I understand case 2. I have explicitly deleted the move constructor, so I get an error if I try to move it. But I would expect that this would also be the case in case 1, where such class is also being moved.
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&&)' }
Note the difference between the two classes. For TestNonMovable
(case 2), you explicitly declare the move constructor as delete
. With TestNonMovable tnm2 = std::move(tnm);
the deleted move constructor is selected in overload resolution and then cause the error.
For SomeClass
(case 1), you don't explicitly declare the move and copy constructor. The copy constructor will be implicitly declared and defined, but the move constructor will be implicitly declared and defined as deleted because it has a non-movable data member. Note the deleted implicitly declared move constructor won't participate in overload resolution. With SomeClass sc2 = std::move(sc1);
, the copy constructor is selected and then the code works fine. The rvalue reference returned from std::move
could be bound to lvalue-reference to const (i.e. const SomeClass&
) too.
The deleted implicitly-declared move constructor is ignored by overload resolution (otherwise it would prevent copy-initialization from rvalue). (since C++14)
BTW: std::move itself is allowed in both cases. It doesn't perform the move operation, it just converts the argument to rvalue. The move operation happens at construction in both cases.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With