繁体   English   中英

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

[英]Return type of '?:' (ternary conditional operator)

为什么第一个返回引用?

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我们有左值、x 值和纯右值。)

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

赋值表达式为对象赋值,因此被赋值的事物必须是左值

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

ISO/IEC 14882:2011 参考:

3.10 [basic.lval] Lvalues 和 rvalues(关于值类别)

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

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

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

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


标准怎么说? ( 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 类型的右值,该右值仍引用原始源类对象(或其适当的子对象)。 [注:即不复制。 — end note ] 通过从 E1 复制初始化 T2 类型的临时对象并将该临时对象用作转换后的操作数。

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

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


5.17/4

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


5.17/5

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

再举一个例子

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM