簡體   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