5
votes

implicitly deleted move constructor (C's move) looks like non-declared move and compiler try to use the copy constructor (C's copy).

Why there is the difference between the implicitly deleted move (C's move) and explicitly deleted move (B's move)?

There are some explanations, are there any more details?

Why is the move constructor neither declared nor deleted with clang?

@dyp comment:

Because an implicitly deleted move constructor is not declared

and link to DR1402:

http://www.open-std.org/JTC1/SC22/WG21/docs/cwg_defects.html#1402

A defaulted move constructor that is defined as deleted is ignored by overload resolution (13.3 [over.match]). [Note: A deleted move constructor would otherwise interfere with initialization from an rvalue which can use the copy constructor instead. —end note]

http://en.cppreference.com/w/cpp/language/move_constructor

(since C++14)The deleted implicitly-declared move constructor is ignored by overload resolution (otherwise it would prevent copy-initialization from rvalue)

sample code:

#include <utility>

class A {
public:
    A() = default;
    A(const A&) = delete;
    A(A&&) = delete;
};

class B : public A {
public:
    B() = default;
    B(const B&) = delete;
    B(B&&) = delete; // explicitly deleted move
};

class C: public A {
public:
    C() = default;
    C(const C&) = default; // implicitly deleted copy because A's copy is deleted
    C(C&&) = default; // implicitly deleted move because A's move is deleted
};

int main() {
    A a1;
    A a2(std::move(a1)); // error, A's move is explicitly deleted

    B b1;
    B b2(std::move(b1)); // error, B's move is explicitly deleted

    C c1;
    C c2(std::move(c1)); // error, C's **copy** is implicitly deleted

    return 0;
}

compiler message:

Apple LLVM version 7.0.0 (clang-700.1.76)
clang++ -std=c++11 3.cpp

3.cpp:26:7: error: call to deleted constructor of 'A'
    A a2(std::move(a1)); // error, A's move is explicited deleted
      ^  ~~~~~~~~~~~~~
3.cpp:7:5: note: 'A' has been explicitly marked deleted here
    A(A&&) = delete;
    ^
3.cpp:29:7: error: call to deleted constructor of 'B'
    B b2(std::move(b1)); // error, B's move is explicited deleted
      ^  ~~~~~~~~~~~~~
3.cpp:14:5: note: 'B' has been explicitly marked deleted here
    B(B&&) = delete; // explicitly deleted move
    ^
3.cpp:32:7: error: call to implicitly-deleted copy constructor of 'C'
    C c2(std::move(c1)); // error, C's **copy** is implicited deleted
      ^  ~~~~~~~~~~~~~
3.cpp:20:5: note: explicitly defaulted function was implicitly deleted here
    C(const C&) = default; // implicitly deleted copy
    ^
3.cpp:17:10: note: copy constructor of 'C' is implicitly deleted because base class 'A' has a deleted copy constructor
class C: public A {
         ^
3.cpp:6:5: note: 'A' has been explicitly marked deleted here
    A(const A&) = delete;
    ^
3 errors generated.
1
I think the difference is only in the compiler message error. - bolov
@bolov they have totally different behaviors. - chyojn
well then I expect an answer. Will learn something new. - bolov
A program that fails to compile has exactly the same behavior as any other program that fails to compile. - n. 1.8e9-where's-my-share m.

1 Answers

1
votes

std::move does not necessarily force moving, it just casts the argument as an xvalue so that it may be moved, if possible. It can be ignored, and is most times unnecessary to call std::move to make the compiler move, or even better optimize copies away completely.

http://en.cppreference.com/w/cpp/utility/move

It is exactly equivalent to a static_cast to an rvalue reference type.

static_cast<typename std::remove_reference<T>::type&&>(t)