隐式移入需要转换操作的 return 语句

Fed*_*dor 5 c++ conversion-operator language-lawyer move-semantics c++20

在 C++20 中,有一条规则,非正式地称为“当返回变量时,首先尝试移动,然后才复制”。

\n

更正式地说是[class.copy.elision]/3

\n
\n

隐式可移动实体是具有自动存储持续时间的变量,它可以是非易失性对象,也可以是对非易失性对象类型的右值引用。在以下复制初始化上下文中,可能会使用移动操作而不是复制操作:

\n
    \n
  • 如果return ([stmt.return])orco_\xc2\xadreturn ([stmt.return.coroutine])语句中的表达式是一个(可能带括号的)id 表达式,它命名在最内层封闭函数或 lambda 表达式的主体或参数声明子句中声明的隐式可移动实体,...
  • \n
\n

首先执行重载决策以选择要复制的构造函数或return_\xc2\xadvalue要调用的重载,就好像表达式或操作数是右值一样。...

\n
\n

让我们考虑一下函数模板

\n
template<typename T>\nT f() {\n    struct {\n        T x;\n        operator T&&() && { return static_cast<T&&>(x); }\n    } s;\n    return s;\n}\n
Run Code Online (Sandbox Code Playgroud)\n

它返回一个自动存储持续时间的变量s。并且有一个采用右值引用的转换运算符&&,可用于构造类型的函数返回值T

\n

我预计由于上述规则,它适用于任何类型T。然而它并没有:

\n
struct A{};\n\nint main() {\n    // ok in GCC and Clang\n    f<A>();\n    // error everywhere\n    //f<int>();\n}\n
Run Code Online (Sandbox Code Playgroud)\n

使用f模板参数调用struct A可以在 Clang 和 GCC 中使用,但不能在 MSVC 中打印错误:

\n
error C2440: \'return\': cannot convert from \'f::<unnamed-type-s>\' to \'T\' with [T=A]\nnote: No user-defined-conversion operator available that can perform this conversion, or the operator cannot be called\n
Run Code Online (Sandbox Code Playgroud)\n

MSVC 这里有一些错误吗?

\n

并且f使用模板参数调用int在任何地方都不起作用。MSVC 的错误是相同的,Clang 现在的错误是:

\n
error: no viable conversion from returned value of type \'struct (unnamed struct at <source>:3:5)\' to function return type \'int\'\nnote: candidate function not viable: expects an rvalue for object argument\n        operator T&&() && { return static_cast<T&&>(x); }\n
Run Code Online (Sandbox Code Playgroud)\n

在线演示: https: //gcc.godbolt.org/z/dfdjEx4v4

\n

当函数返回像这样的类类型A而不是像这样的标量类型时,是否期望该规则起作用int

\n