我可以理解编译器正在下面的代码中执行 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中引起我注意的句子,这似乎表明复制构造函数应该在重载决议中被考虑:
如果第一个重载决策失败或未执行,或者如果 所选构造函数的第一个参数的类型不是 rvalue引用对象的类型(可能是cv-qualified), 再次执行重载决策,将对象视为 左值。
修改
从下面的T.C.之一的评论中,我理解当要复制的对象由rvalue指定时,编译器根据§12.8/ 32,不认为复制构造函数为副本的候选人,即使副本将被删除。也就是说,最终结果将是使用默认构造函数构造对象s
。相反,在这种情况下,标准规定(其中??)代码是不正确的。除非我对这个方案的理解完全错误,否则对我来说没有任何意义。
答案 0 :(得分:2)
这与复制省略或构造函数无关;它只是重载决议。
如果我们有一对重载:
void f( T&& rv );
void f( const T& lv );
然后重载决策规则说f( T{} )
更适合f(T&&)
。
复制elision可以删除副本或移动,但仅在代码定义良好时(即使编译器选择不实现复制省略)。您的代码没有明确定义,因为它指定调用已删除的函数。