返回类型'?:'(三元条件运算符)

时间:2011-12-16 13:57:39

标签: c++ types reference conditional-operator lvalue

为什么第一个返回引用?

int x = 1;
int y = 2;
(x > y ? x : y) = 100;

虽然第二个没有?

int x = 1;
long y = 2;
(x > y ? x : y) = 100;

实际上,第二个根本没有编译 - “没有左边的赋值”。

3 个答案:

答案 0 :(得分:173)

表达式没有返回类型,它们具有类型和 - 在最新的C ++标准中已知 - 值类别。

条件表达式可以是左值右值。这是它的价值类别。 (这有点简化,C++11我们有左值,x值和prvalues。)

用非常宽泛和简单的术语来说, lvalue 指的是内存中的一个对象,而 rvalue 只是一个可能不一定附加到内存中的对象的值

赋值表达式为对象赋值,因此分配给的对象必须是左值

对于条件表达式(?:)是左值(同样,在广义和简单的术语中),第二个和第三个操作数必须是 lvalues < / em>相同类型。这是因为条件表达式的类型和值类别是在编译时确定的,并且必须是适当的,无论条件是否为真。如果其中一个操作数必须转换为另一个类型以匹配另一个操作数,则条件表达式不能是 lvalue ,因为此转换的结果不是 lvalue

  

ISO / IEC 14882:2011参考文献:

     

3.10 [basic.lval]左值和右值(关于值类别)

     

5.15 [expr.cond]条件运算符(条件表达式具有的类型和值类别的规则)

     

5.17 [expr.ass]赋值和复合赋值运算符(要求赋值的l.h.s.必须是可修改的左值)

答案 1 :(得分:56)

三元?:表达式的类型是其第二和第三个参数的常见类型。如果两种类型相同,则返回引用。如果它们可以相互转换,则选择一个,另一个转换(在这种情况下提升)。由于您无法返回临时(转换/提升变量)的左值引用,因此其类型为值类型。

答案 2 :(得分:17)

它无法返回左值,因为它必须隐式提升x的类型以匹配y的类型(因为:的两边不是同一类型),并且必须创建一个临时的。


标准说什么? (n1905

表达式5.17分配和复合赋值运算符

  

<强> 5.17 / 3

     

如果第二个和第三个操作数具有不同的类型,并且具有(可能是cv-qualified)类类型,则尝试将每个操作数转换为另一个操作数的类型。确定类型T1的操作数表达式E1是否可以转换为匹配类型T2的操作数表达式E2的过程定义如下:

     

- 如果E2是左值:如果可以将E1隐式转换(第4节)到类型“引用到T2”,则E1可以转换为匹配E2,受限于在转换中引用必须直接绑定( 8.5.3)到E1。

     

- 如果E2是右值,或者上述转换无法完成:

     

- 如果E1和E2具有类类型,并且底层类类型相同或者一个是另一个的基类:如果T2的类与类型相同,则可以将E1转换为匹配E2,或者基类,T1的类和T2的cv资格是与cv资格相同的cv资格,或者更高的cv资格。如果应用转换,则将E1更改为类型T2的右值,该值仍然引用原始源类对象(或其相应的子对象)。 [注意:即没有复制。 - 结束注释]通过从E1复制初始化T2类型的临时值并将该临时值用作转换后的操作数。

     

否则(即,如果E1或E2具有非类型类型,或者它们都具有类类型但基础类不是相同的或一个是另一个的基类):E1可以是转换为匹配E2,如果E1可以隐式转换为表达式E2,如果E2被转换为右值(或者它具有的类型,如果E2是右值),则该表达式将被转换为。

     

使用此过程,确定是否可以转换第二个操作数以匹配第三个操作数,以及是否可以转换第三个操作数以匹配第二个操作数。如果两者都可以转换,或者一个可以转换,但转换不明确,则程序格式不正确。如果两者都不能被转换,则操作数保持不变并且如下所述执行进一步检查。如果只能进行一次转换,则将该转换应用于所选操作数,并使用转换后的操作数代替本节其余部分的原始操作数。


  

<强> 5.17 / 4

     

如果第二个和第三个操作数是左值并且具有相同的类型,则结果是该类型并且是左值,如果第二个或第三个操作数是位字段,则它是位字段,或者如果两者都是是位字段。


  

<强> 5.17 / 5

     

否则,结果是右值。如果第二个和第三个操作数不具有相同的类型,并且具有(可能是cv限定的)类类型,则使用重载决策来确定要应用于操作数的转换(如果有)(13.3.1.2,13.6) 。如果重载决策失败,则程序格式错误。否则,应用如此确定的转换,并使用转换的操作数代替本节其余部分的原始操作数。