繁体   English   中英

仅移动类型返回到转换构造函数

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM