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

时间:2015-08-02 19:42:26

标签: c++ language-lawyer c++14 copy-elision

我可以理解编译器正在下面的代码中执行 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。相反,在这种情况下,标准规定(其中??)代码是不正确的。除非我对这个方案的理解完全错误,否则对我来说没有任何意义。

1 个答案:

答案 0 :(得分:2)

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

如果我们有一对重载:

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

然后重载决策规则说f( T{} )更适合f(T&&)

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