[英]Should a constructor for a class that contains a move-only type receive the move-only type by reference or by rvalue reference?
[英]Move-only type returned into converting constructor
以下代码返回仅移动类型,然后应由转换构造函数转换为另一种类型。
#include <utility>
class Foo
{
public:
Foo() {}
Foo(const Foo&) = delete;
Foo(Foo&&) = default;
};
class Other
{
public:
Other(Foo foo) {}
};
Other moo()
{
Foo foo;
return foo;
}
int main()
{
moo();
}
这给我的编译器带来了一个错误,只能通过将std::move
添加到被认为是不良做法的return语句来修复,因为通常它会阻止返回值优化。 为了满足转换,首先应该将return语句的标识符视为rvalue吗?
这段代码是否有效,哪个编译器就在这里?
为了满足转换,首先应该将return语句的标识符视为rvalue吗?
是的,不是。 来自[class.copy] ,作为CWG 1579的结果(此处的措辞是从C ++ 17中复制的,虽然它在C ++ 14中是相同的。我发现子弹比早期的语法选择更容易阅读詹姆斯乔伊斯脸红......):
在以下复制初始化上下文中,可能会使用移动操作而不是复制操作:
- 如果
return
语句中的表达式是一个(可能带括号的)id-expression,它指定一个对象,该对象具有在最内层封闭函数或lambda表达式的body或parameter-declaration-clause中声明的自动存储持续时间,或者- [...]
首先执行重载决策以选择副本的构造函数,就好像该对象是由rvalue指定的一样。 如果第一个重载决策失败或未执行,或者所选构造函数的第一个参数的类型不是对象类型的rvalue引用 (可能是cv-qualified),则再次执行重载决策,将对象视为左值。
第一个子弹在这里适用,所以我们首先进行重载解析,好像foo
是一个rvalue。 这是通过Foo(Foo&& )
获得的Other(Foo )
构造函数。
Other(Foo )
的第一个参数不是右值引用,所以我们应该再次进行重载分辨,将foo
作为左值,它会失败。 这似乎是一个不必要的限制,但我在这里打电话给clang是正确的。 如果将构造函数更改为Other(Foo&& )
,则clang接受它。
巴里的答案很好地涵盖了标准规则,但我有一个实际的建议:
并且只能通过将
std::move
添加到被认为是不良做法的return语句来修复,因为通常它会阻止返回值优化。
你的担心是没有道理的。 NRVO无论如何都不适用于转换,并允许RVO对移动结果。 明确的举动很好。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.