以下代码返回一个只迁移类型,然后由转换构造函数转换为另一种类型。
,
这使我的编译器出错,只能通过将,
添加到被认为是不良做法的return语句来修复,因为通常它会阻止返回值优化。不应该首先将return语句的标识符视为rvalue以满足转换吗?
此代码是否有效以及哪个编译器就在这里?
答案 0 :(得分:4)
不应该首先将return语句的标识符视为rvalue以满足转换吗?
是和否。 [class.copy]的结果来自CWG 1579(此处的措辞是从C ++ 17中复制的,虽然它在C++14中是相同的。我发现子弹比早期的语法更容易阅读让詹姆斯乔伊斯脸红的选择......):
在以下复制初始化上下文中,可能会使用移动操作而不是复制操作:
首先执行
- 如果
return
语句中的表达式是一个(可能带括号的)id-expression,它指定一个对象,该对象具有在最内层封闭函数或lambda-expression的body或parameter-declaration-clause中声明的自动存储持续时间,或- [...]
重载决策以选择复制的构造函数,就好像该对象是由rvalue指定的一样。如果第一个重载决策失败或未执行,或如果所选构造函数的第一个参数的类型不是对象类型的右值引用(可能是cv-qualified),则执行重载决策再次,将对象视为左值。
第一个项目符号适用于此处,因此我们首先执行重载解析,就像foo
是右值一样。这是通过Other(Foo )
到Foo(Foo&& )
构造函数的。
Other(Foo )
的第一个参数不是右值引用,因此我们应该再次进行重载解析,将foo
视为左值,这会失败。这似乎是一个不必要的限制,但我在这里打电话给clang是正确的。如果将构造函数更改为Other(Foo&& )
,则clang接受它。
答案 1 :(得分:2)
巴里的好答案涵盖了标准规则,但我有一个实际的建议:
并且只能通过将
std::move
添加到被认为是不良做法的return语句来修复,因为通常它会阻止返回值优化。
你的担心是没有道理的。 NRVO无论如何都不适用于转换,并允许RVO对移动结果。明确的举动很好。