在执行复制省略时,当移动构造函数被删除时,编译器不会在重载决策中考虑复制构造函数。为什么?

While doing copy-elision, the compiler doesn't consider the copy constructor in overload resolution, when the move constructor is deleted. Why?

我可以理解编译器正在下面的代码中执行 copy-elision,因为在所谓的 copy-initialization 中没有调用复制和移动构造函数main()。参见 live example

#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(); 
}

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

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

int main() {
    S s = S(); 
}

在本例中,我在 §12.8/32 (N4140) 中找不到任何可以禁止使用或删除 复制构造函数 的内容。这是§12.8/32中引起我注意的那句话,这似乎表明复制构造函数应该在重载决议中被考虑:

If the first overload resolution fails or was not performed, or if the type of the first parameter of the selected constructor is not an rvalue reference to the object’s type (possibly cv-qualified), overload resolution is performed again, considering the object as an lvalue.

编辑

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

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

如果我们有一对重载:

void f( T&& rv );
void f( const T& lv );

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

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