6

我可以理解编译器在下面的代码中进行了复制省略,因为在所谓的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(); 
}

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

#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 节中引起我注意的一句话,这似乎表明应该在重载决议中考虑复制构造函数:

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

编辑

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

4

1 回答 1

2

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

如果我们有一对重载:

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

然后重载决议规则说这f( T{} )是一个更好的匹配f(T&&).

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

于 2015-08-03T00:07:05.967 回答