将返回的左值隐式处理为右值

fre*_*low 19 c++ return move-semantics c++11

12.8复制和移动类对象[class.copy]§31和§32说:

在具有类返回类型的函数的return语句中,当表达式是具有与函数返回类型相同的cv-unqualified类型的非易失性自动对象(函数或catch子句参数除外)的名称时,通过将自动对象直接构造到函数的返回值中,可以省略复制/移动操作

当满足或将满足复制操作的省略标准时,除了源对象是函数参数这一事实,并且要复制的对象由左值指定,重载决策选择复制的构造函数是首先执行,好像对象是由右值指定的.

因此我们可以写:

unique_ptr<int> make_answer()
{
    unique_ptr<int> result(new int(42));
    return result;   // lvalue is implicitly treated as rvalue
}
Run Code Online (Sandbox Code Playgroud)

但是,我注意到g ++ 4.6.3也接受不是名称的左值,例如:

    return (result);
    return *&result;
    return true ? result : result;
Run Code Online (Sandbox Code Playgroud)

相比之下,return rand() ? result : result;不起作用.编译器的优化器是否会干扰语言语义?当我解释标准时,return (result);不应该编译,因为(result)它不是名称,而是带括号的表达式.我是对还是错?

Fil*_*efp 10

关于括号表达式 [√]

在讨论带括号的表达式时你错了,并且它在返回时不应该触发移动并且只包含可移动对象的名称.

5.1.1/1一般[expr.prim.general]

带括号的表达式是一个主表达式,其类型和值与所包含表达式的类型和值相同.括号的存在不会影响表达式是否为左值.除非另有说明,否则括号的表达式可以在可以使用所包含的表达式的上下文完全相同的上下文中使用,并且具有相同的含义.


关于constexpr 条件运算符 [╳]

我在常量表达式编码运算符中解释标准的方式是使用return true ? result : result表现良好,因为它是一个常量表达式,因此等同于返回结果;

我现在更仔细地阅读了标准,并且没有任何地方说它是一个恒定的条件表达式,就像只写了"返回"表达式一样.

true ? <expr1> : <expr2>; // this is not the same as just writing <expr1>;
Run Code Online (Sandbox Code Playgroud)

关于退货*&结果; [╳]

在C99中明确指出,*&result恰好等同于编写,result而不是C++规范中的情况.

虽然我们都同意,使用*&result将确实产生相同的左值result,但根据标准*&result(当然)不是其中一个表达式"的表达是一种非挥发性的自动对象的名称".

当然,表达式包含一个合适的名称,但不仅如此.


总结一下......

return result; // #1, OK
Run Code Online (Sandbox Code Playgroud)

return (result);                  // as described earlier, OK
return true ? result : result;    // as described earlier, ill-formed
return rand () ? result : result; // as described earlier, ill-formed
return *&result;                  // as described earlier, ill-formed
Run Code Online (Sandbox Code Playgroud)

  • 我不太确定.三元运算符可用于例如`constexpr`函数或数组索引. (4认同)
  • 第二种情况也应该是格式错误的,因为三元运算符是*表达式*并且不表示自动对象的名称.优化不允许更改程序的可观察行为(复制省略等). (2认同)