返回类型为“?:”(三进制条件运算符)


208

为什么第一个返回引用?

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

虽然第二个没有?

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

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


1
嗯,就像找到烤面包的特殊情况一样,这一次
没来过


由于将类型分配给表达式将意味着至少要转换一个项,因此该项将不再是l值。
Yves Daoust

Answers:


173

表达式没有返回类型,它们具有一个类型,并且(如最新的C ++标准所知)具有一个值类别。

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

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

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

对于条件表达式(?:)是一个左值(再次,在广泛的和简单的术语),所述第二和第三操作数必须是左值的相同类型的。这是因为条件表达式的类型和值类别是在编译时确定的,并且无论条件是否为真都必须适当。如果必须将一个操作数转换为其他类型以与另一个匹配,则条件表达式不能为左值,因为此转换的结果将不是左值

ISO / IEC 14882:2011参考:

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

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

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


3
当阅读xvalue和prvalue时(因为在您回答之前我从未听说过它们),我遇到了这个方便的SO帖子:stackoverflow.com/questions/3601602/…–
蓬松的

an rvalue is just a value that may not necessarily be *attached* to an object in memory.您能用更简单的术语来解释吗?。另外,你是什么意思type and value *category*?谢谢
Mr.Anubis'4

@SoulReaper:prvalue, xvalue, glvalue是值类别。
Xeo 2012年

@Xeo我非常感谢您的帮助,但是您能说出“ 右值”是什么意思,它只是一个值,不一定附加到内存中的对象上。?有例子吗?
阿努比斯先生2012年

@SoulReaper:我想他静下心来truethisenum值。这些东西是prvalues(“纯” rvalues),但不存在于内存中。
Xeo 2012年

57

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


但y大于x,因此在特殊情况下无需升级,它可以返回对y的引用。嗯...但是我同意,这很奇怪。
Yola

1
@ Mr.TAMER:我宁愿深入了解标准。:<
Xeo

3
@Yola:由于类型是C ++中的编译时概念,因此表达式的实际返回无关紧要。
Xeo

1
您没有得到参考,您得到了左值。
Suma

1
@Xeo:虽然不是C ++术语;)
Sebastian Mach

19

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


标准怎么说?(n1905

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

5.17 / 3

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

—如果E2是左值:如果可以将E1隐式转换为“对T2的引用”类型,则可以将E1转换为与E2匹配,但要满足以下条件:在转换中,引用必须直接绑定(8.5.3) )到E1。

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

—如果E1和E2具有类类型,并且基础类类型相同,或者一个是另一类的基类:如果T2的类是与E2相同的类型,则可以将E1转换为匹配E2。 ,T1的类别和T2的cv资格与t1的cv资格相同,或具有比T1的cv资格更大的cv资格。如果应用了转换,则将E1更改为类型T2的右值,该值仍引用原始源类对象(或其适当的子对象)。[ 注意:即不进行复制。通过使用E1复制初始化类型T2的临时对象并将该临时对象用作转换后的操作数,来将其作为结尾

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

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


5.17 / 4

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


5.17 / 5

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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.