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

为什么第一个返回一个引用?

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

而第二个不?

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

实际上,第二个根本没有编译 - “不是左值任务”。


表达式没有返回类型,它们有一个类型,并且 - 正如它在最新的C ++标准中已知的 - 是一个值类别。

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

用非常宽泛和简单的术语来说,左值指的是内存中的对象,而右值只是一个值,不一定会附加到内存中的对象。

赋值表达式将一个值赋给一个对象,所以被赋值的对象必须是一个左值。

对于一个条件表达式( ?: :)来说是一个左值(同样,宽泛且简单), 第二个和第三个操作数必须是相同类型的左值。 这是因为条件表达式的类型和值类别是在编译时确定的,无论条件是否为真都必须适当。 如果其中一个操作数必须转换为不同的类型以匹配另一个,那么该条件表达式不能是左值,因为此转换的结果不会是左值。

ISO / IEC 14882:2011参考文献:

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

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

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


三元?:表达式的类型是其第二个和第三个参数的常见类型。 如果两种类型都相同,则返回参考。 如果他们可以相互转换,一个会被选中,另一个会被转换(在这种情况下被提升)。 由于您不能将左值引用返回到临时(转换/升级的变量),因此其类型是值类型。


它不能返回左值,因为它必须隐含地提升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的类与类型相同,或者基类为,T1的等级和T2的cv资格与T1的cv资格相同,或者更高的cv资格。 如果应用了转换,则E1被改变为仍然引用原始源类对象(或其适当的子对象)的类型T2的右值。 [注意:也就是说,不做任何复制。 通过从E1中复制初始化T2类型的临时文件并将该临时文件用作转换后的操作数来结束注释]。

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

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


5.17 / 4

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


5.17 / 5

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

链接地址: http://www.djcxy.com/p/78637.html

上一篇: Return type of '?:' (ternary conditional operator)

下一篇: How dangerous is it to compare floating point values?