'?:' 的结果类型是什么? (三元/条件运算符)?

发布于 2024-12-21 13:58:09 字数 366 浏览 2 评论 0原文

为什么第一个条件运算符会产生引用?

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

然而,第二个却没有。

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

实际上,第二个根本无法编译:

错误:需要左值作为赋值的左操作数
      | (x>y?x:y)=100;
      | ~~~~~~~^~~~~~~~

Why does the first conditional operator result in a reference?

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

However, the second does not.

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

Actually, the second does not compile at all:

error: lvalue required as left operand of assignment
      |     (x > y ? x : y) = 100;
      |     ~~~~~~~^~~~~~~~

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

謌踐踏愛綪 2024-12-28 13:58:09

表达式没有返回类型,它们有一个类型和(自 C++11 标准以来众所周知的)值类别。

条件表达式可以是左值右值。这是它的价值类别。 (这在某种程度上是一种简化,在C++11中,我们有左值、x值和纯右值。)

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

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

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

ISO/IEC 14882:2011 参考资料:

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

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

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

Expressions don't have return types, they have a type and - as it's known since the C++11 standard - a value category.

A conditional expression can be an lvalue or an rvalue. This is its value category. (This is somewhat of a simplification, in C++11 we have lvalues, xvalues and prvalues.)

In very broad and simple terms, an lvalue refers to an object in memory and an rvalue is just a value that may not necessarily be attached to an object in memory.

An assignment expression assigns a value to an object so the thing being assigned to must be an lvalue.

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 references:

3.10 [basic.lval] Lvalues and rvalues (about value categories)

5.15 [expr.cond] Conditional operator (rules for what type and value category a conditional expression has)

5.17 [expr.ass] Assignment and compound assignment operators (requirement that the l.h.s. of an assignment must be a modifiable lvalue)

誰ツ都不明白 2024-12-28 13:58:09

三元 ?: 表达式的类型是其第二个和第三个参数的公共类型。如果两种类型相同,您会得到一个参考。如果它们可以相互转换,则选择一个并转换另一个(在本例中为升级)。由于您无法返回对临时变量(转换/提升的变量)的左值引用,因此它的类型是值类型。

The type of the ternary ?: expression is the common type of its second and third argument. If both types are the same, you get a reference back. If they are convertable to each other, one gets chosen and the other gets converted (promoted in this case). Since you can't return an lvalue reference to a temporary (the converted / promoted variable), its type is a value type.

吻泪 2024-12-28 13:58:09

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


标准怎么说? (n1905)

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

5.17/3

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

—如果 E2 是左值:如果 E1 可以隐式转换(第 4 条)为“对 T2 的引用”类型,则 E1 可以转换为匹配 E2,但要遵守转换中引用必须直接绑定的约束( 8.5.3) 至 E1。

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

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

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

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


5.17/4

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


5.17/5

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

It cannot return a lvalue since it will have to implicitly promote the type of x to match the type of y (since both sides of : are not of the same type), and with that it has to create a temporary.


What does the standard say? (n1905)

Expressions 5.17 Assignment and compound assignment operators

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

If the second and third operands are lvalues and have the same type, the result is of that type and is an lvalue and it is a bit-field if the second or the third operand is a bit-field, or if both are bit-fields.


5.17/5

Otherwise, the result is an rvalue. If the second and third operands do not have the same type, and either has (possibly cv-qualified) class type, overload resolution is used to determine the conversions (if any) to be applied to the operands (13.3.1.2, 13.6). If the overload resolution fails, the program is ill-formed. Otherwise, the conversions thus determined are applied, and the converted operands are used in place of the original operands for the remainder of this section.

就像说晚安 2024-12-28 13:58:09

再举一个例子

    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 =)

One more example

    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 =)
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文