为什么第一个返回引用?
int x = 1;
int y = 2;
(x > y ? x : y) = 100;
而第二个不是?
int x = 1;
long y = 2;
(x > y ? x : y) = 100;
实际上,第二个根本没有编译——“not lvalue left of assignment”。
为什么第一个返回引用?
int x = 1;
int y = 2;
(x > y ? x : y) = 100;
而第二个不是?
int x = 1;
long y = 2;
(x > y ? x : y) = 100;
实际上,第二个根本没有编译——“not lvalue left of assignment”。
三元?:表达式的类型是它的第二个和第三个参数的公共类型。如果两种类型相同,则返回引用。如果它们可以相互转换,则选择一个,转换另一个(在本例中为提升)。由于不能返回对临时变量(已转换/提升的变量)的左值引用,因此它的类型是值类型。
它不能返回左值,因为它必须隐式地提升x的类型以匹配y的类型(因为:的两边不属于同一类型),因此它必须创建一个临时类型。
标准是怎么说的?(n1905)
赋值运算符和复合赋值运算符
5.17/3 If the second and third operand have different types, and either has (possibly cv-qualified) class type, an attempt is made to convert each of those operands to the type of the other. The process for determining whether an operand expression E1 of type T1 can be converted to match an operand expression E2 of type T2 is defined as follows: — If E2 is an lvalue: E1 can be converted to match E2 if E1 can be implicitly converted (clause 4) to the type “reference to T2”, subject to the constraint that in the conversion the reference must bind directly (8.5.3) to E1. — If E2 is an rvalue, or if the conversion above cannot be done: — if E1 and E2 have class type, and the underlying class types are the same or one is a base class of the other: E1 can be converted to match E2 if the class of T2 is the same type as, or a base class of, the class of T1, and the cv-qualification of T2 is the same cv-qualification as, or a greater cv-qualification than, the cv-qualification of T1. If the conversion is applied, E1 is changed to an rvalue of type T2 that still refers to the original source class object (or the appropriate subobject thereof). [Note: that is, no copy is made. — end note] by copy-initializing a temporary of type T2 from E1 and using that temporary as the converted operand. Otherwise (i.e., if E1 or E2 has a non class type, or if they both have class types but the underlying classes are not either the same or one a base class of the other): E1 can be converted to match E2 if E1 can be implicitly converted to the type that expression E2 would have if E2 were converted to an rvalue (or the type it has, if E2 is an rvalue). Using this process, It is determined whether the second operand can be converted to match the third operand, and whether the third operand can be converted to match the second operand. If both can be converted, or one can be converted but the conversion is ambiguous, the program is ill-formed. If neither can be converted, the operands are left unchanged and further checking is performed as described below. If exactly one conversion is possible, that conversion is applied to the chosen operand and the converted operand is used in place of the original operand for the remainder of this section.
5.17 / 4 如果第二个和第三个操作数是左值并且具有相同的类型,则如果第二个或第三个操作数是位字段,或者两者都是位字段,则结果是该类型的左值并且是位字段。
5.17/5 否则,结果为右值。如果第二个和第三个操作数没有相同的类型,并且其中一个有(可能是cv限定的)类类型,则使用重载解析来确定要应用于操作数的转换(如果有的话)(13.3.1.2,13.6)。如果重载解析失败,则程序是病态的。否则,将应用由此确定的转换,并在本节剩余部分中使用转换后的操作数代替原始操作数。
表达式没有返回类型,它们有一个类型和一个值类别——在最新的c++标准中这是众所周知的。
条件表达式可以是左值,也可以是右值。这是它的价值类别。(这是一种简化,在c++ 11中我们有左值,x值和pr值。)
在非常广泛和简单的术语中,左值指的是内存中的对象,而右值只是一个不一定附加到内存中的对象的值。
赋值表达式为对象赋值,因此被赋值的对象必须是左值。
For a conditional expression (?:) to be an lvalue (again, in broad and simple terms), the second and third operands must be lvalues of the same type. This is because the type and value category of a conditional expression is determined at compile time and must be appropriate whether or not the condition is true. If one of the operands must be converted to a different type to match the other then the conditional expression cannot be an lvalue as the result of this conversion would not be an lvalue.
ISO/IEC 14882:2011参考文献: 3.10基本。lval]左值和右值(关于值类别) 5.15 [expr。条件运算符(条件表达式的类型和值类别的规则) 5.17 [expr。赋值和复合赋值操作符(要求赋值的l.h.s.必须是可修改的左值)
再举一个例子
int x = 1;
int y = 2;
long z = 3;
(true ? x : y) = 100; // x & y are SAME type so it returns Lvalue(so it can be LHS of =). x = 100, y = 2
(false ? x : y) = 100; // x & y are SAME type so it returns Lvalue(so it can be LHS of =). x = 1 , y = 100
// (true ? x : z) = 100; // Error: x & z are DIFFERENT types so it returns Rvalue (so it can NOT be LHS of =)
// (false ? x : z) = 100; // Error: x & z are DIFFERENT types so it returns Rvalue (so it can NOT be LHS of =)