在执行copy-elision时,编译器在删除移动构造函数时不会考虑重载解析中的复制构造函数.为什么?

Fra*_*uet 6 c++ language-lawyer copy-elision c++14

我可以理解编译器正在下面的代码中执行copy-elision,因为复制和移动构造函数不会在所谓的copy-initializationdone in中调用main().查看实例.

#include <iostream>
struct S {
    S() = default;
    S(const S&) { std::cout << "copy ctor" << '\n'; }
    S(S&&) { std::cout << "move ctor" << '\n'; }
};

int main() {
    S s = S(); 
}
Run Code Online (Sandbox Code Playgroud)

但是当我删除移动构造函数时,我无法理解为什么代码不能编译,如下所示:

#include <iostream>
struct S {
    S() = default;
    S(const S&) { std::cout << "copy ctor" << '\n'; }
    S(S&&) = delete;
};

int main() {
    S s = S(); 
}
Run Code Online (Sandbox Code Playgroud)

在这种情况下,我在§12.8/ 32(N4140)中找不到任何可能禁止使用或省略复制构造函数的内容.这是在§12.8/ 32中引起我注意的句子,这似乎表明复制构造函数应该在重载决策中被考虑:

如果第一个重载决策失败或未执行,或者所选构造函数的第一个参数的类型不是对象类型的rvalue引用(可能是cv-qualified),则再次执行重载决策,将对象视为左值.

编辑

从以下TC的评论之一,我理解当要复制的对象由右值指定时,编译器根据§12.8/ 32,不认为复制构造函数是副本的候选者,甚至虽然副本无论如何都会被删除.也就是说,最终结果将是s使用默认构造函数构造对象.相反,在这种情况下,标准要求(在哪里??)代码是不正确的.除非我对这个方案的理解完全错误,否则对我来说没有任何意义.

M.M*_*M.M 1

这与复制省略或构造函数无关;这只是重载解析。

如果我们有一对重载:

void f( T&& rv );
void f( const T& lv );
Run Code Online (Sandbox Code Playgroud)

那么重载解析规则表明f( T{} )更适合f(T&&).

复制省略可以省略复制或移动,但前提是代码定义良好(即使编译器选择不实现复制省略)。您的代码定义不明确,因为它指定调用已删除的函数。