为什么隐式删除移动构造函数调用复制构造函数?

chy*_*ojn 5 constructor move c++11

隐式删除的移动构造函数(C 的移动)看起来像未声明的移动,编译器尝试使用复制构造函数(C 的复制)。

为什么存在差异之间隐含删除移动(C的举动),并明确删除移动(B的举动)?

有一些解释,还有更多细节吗?

为什么移动构造函数既没有用 clang 声明也没有删除?

@dyp 评论:

因为没有声明隐式删除的移动构造函数

并链接到 DR1402:

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

定义为已删除的默认移动构造函数会被重载决议 (13.3 [over.match]) 忽略。[注意:删除的移动构造函数会干扰从可以使用复制构造函数代替的右值的初始化。——尾注]

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

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

示例代码:

#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;
}
Run Code Online (Sandbox Code Playgroud)

编译器消息:

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.
Run Code Online (Sandbox Code Playgroud)

J.P*_*.P. 1

std::move 不一定强制移动,它只是将参数转换为 xvalue,以便在可能的情况下可以移动它。它可以被忽略,并且大多数时候没有必要调用 std::move 来使编译器移动,甚至更好地完全优化副本。

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

它完全等同于 static_cast 到右值引用类型。

static_cast<typename std::remove_reference<T>::type&&>(t)
Run Code Online (Sandbox Code Playgroud)