2011-05-08 113 views
13

(由an answer提示。)什麼是decltype(0 + 0)?

鑑於N3290,§7.1.6.2p4,這裏的列表項是無編號,但編號在這裏爲我們的方便:

通過decltype表示的類型(E )被定義爲如下:

  1. 如果e是一個括號的ID-表達或加括號的類的成員訪問(5.2.5),decltype(e)是通過e命名實體的類型。如果沒有這樣的實體,或者如果e名稱是一組重載函數,則該程序是不合格的;如果e是x值,則decltype(e)是T & &,其中T是e的類型;否則,如果e是左值,則decltype(e)是T &,其中T是e的類型;如果e是左值,則decltype(e)是T &,其中T是e的類型;
  2. 否則,decltype(e)是e的類型。

decltype(0 + 0)指定的類型是什麼?

第1項不適用,2可能,但如果不適用,則3不適用,4將是結果。那麼,什麼是xvalue,是0 + 0還是xvalue?

§3.10p1:

的x值(一個「到期」值)也指一個對象,通常接近其壽命的末尾(使得其資源可以被移動,例如)。 xvalue是涉及右值引用的某些表達式的結果(8.3.2)。

我沒有在§8.3.2中看到任何有用的東西,但我知道「0 + 0」不涉及任何右值引用。文字0是一個prvalue,它是「不是一個xvalue的右值」(§3.10p1)。我相信「0 + 0」也是一個價值。如果是這樣,「decltype(0 + 0)」將是int(不是int & &)。

我錯過了我的解釋?這段代碼是否合格?

decltype(0 + 0) x; // Not initialized. 

代碼在GCC 4.7.0 20110427和Clang 2.9(中繼線126116)上編譯。例如,如果decltype指定了一個int & &類型,那麼它將不會完好。

+3

我沒有看到你的推理有什麼問題。我相信'decltype(0 + 0)'也應該是'int'。 – 2011-05-08 00:36:00

+1

FWIW,肯定的一個好的答案是擴展xvalue的定義並展示它的可能和不可能。 (我會發現*非常有用)。我需要看看如何重新說明,關注「什麼是xvalue?」同時仍然考慮這個「0 + 0」的具體情況。 – 2011-05-08 00:43:00

+3

雖然最新的草案確實爲很多表達式指定了_value category_,包括後綴增量和3.10中的一個註釋,表明第5條應該顯示每個內置操作符的值的類別,但似乎沒有提到草案任何二元運算符的值類別從5.6到5.15,除非我的搜索能力讓我失敗。 – 2011-05-08 00:58:33

回答

2

從5.19 [expr.const],每常量表達式是prvalue 。

常量表達式是文本類型的prvalue核心常量表達式,但是沒有指針類型。 積分常量表達式是積分或非範圍枚舉類型的文字常量表達式。

因此規則4適用於所有文字常量表達式。

+0

謝謝,雖然我仍然在「int n = 42; decltype(0 + n)」的語義中看到了一個漏洞(正如Charles在對該問題的評論中指出的)。 :( – 2011-06-03 02:00:15

+0

@Fred:當然,雖然標準清楚地表明'0 + 0'是一個*核心常量表達式*,它的* prvalue *狀態仍然存在疑問。顯然,如果它不是* prvalue *它不能是一個整型常量表達式,並且很多東西會被打破 – 2011-06-03 02:02:26

+2

你有這個倒退:該段落是**定義**術語*文字常量表達式* – 2012-03-21 06:40:05

0

GCC說int -

代碼:

#include <iostream> 
#include <typeinfo> 

int 
main() 
{ 
    int n; 
    decltype(0 + 0) x; 
    std::cout << "Type of `n': " << typeid(n).name() << std::endl; 
    std::cout << "Type of `x': " << typeid(x).name() << std::endl; 
} 

輸出:

編輯:根據第4點它是有道理的,但我不能肯定地說第2點實際上並不是實際的效果。根據我所知,0 + 0評估爲0,而0的類型爲int,因此這是已聲明的類型。

+1

但是它對int &&和int類似:http:// ideone .com/6c6N6 – 2011-05-08 00:51:29

+0

的確如此。請注意,對於GCC,int &&與int相同。畢竟,對int的引用是一個int。畢竟,參考只是理論上的一個別名。嘗試'if(typeid(int)== typeid(int &&)){std :: cout <<「int == int &&」<< std :: endl; }'。即使它們的字符串是相同的,實際的typeid也不會相同,除非它們被完全對待。這讓我想知道它下面發生了什麼......現在,我會說'decltype(0 + 0)'產生'int'類型。 – 2011-05-08 01:11:35

2

您的推理是正確的。僅涉及常量的表達式本身就是一個常量。因此

decltype(0 + 0) x; 

等於

decltype(0) x; 

其等於

int x; 
+1

這不回答這個問題。使用零是一個佔位符,並且一個好的答案將顯示如何推斷decltype(some_int + another_int)(或顯示爲什麼零文字是特殊的)。 – 2011-05-10 09:14:28

9

0 + 0是二prvalues的表達,(n3290參數3.10),其適用於內置operator+,其中,每13.6/12是LR operator+(L,R),這是一個返回非參考值的函數。表達的結果也是一個價值(按3.10)。

因此,0 + 0的結果是一個prvalue,0是int,因此0 + 0的結果是一個int

+2

§13.6p9是*一元*運算符+。你需要§13.6p12。然而,草案指出:「這些候選職能參與13.3.1.2中描述的運營商重載決策過程,並且不得用於其他目的。」 (§13.6p1)我認爲「沒有其他目的」意味着我們不能用它們來確定價值類別。無論如何,+1是一個很好的答案。 – 2011-05-08 02:59:41

+0

@FredNurk - 我編輯了參考。我一定很累...... – rlc 2011-05-08 03:07:33

+3

內置的運算符不是函數調用。所以你不能拿13.6/12並得到這些候選者的描述返回類型,並將它們應用回第5條。那些13.6的候選者只有在重載解析時纔是有效的和相關的(如果至少有一個操作數是類或枚舉類型的)。它們僅用於轉換類類型操作數。在完成之後,控制完全返回到第5節。「LR操作符+」不是實際調用的函數。 – 2011-05-12 05:02:31

5

這絕對是一個int:

#include <iostream> 
#include <typeinfo> 

template<typename T> 
struct ref_depth 
{ 
     enum { value = 0 }; 
}; 

template<typename T> 
struct ref_depth<T&> 
{ 
     enum { value = 1 }; 
}; 

template<typename T> 
struct ref_depth<T&&> 
{ 
     enum { value = 2 }; 
}; 

int main() { 

    std::cout 
    << "int: " << typeid(int).name() << "\n" 
     "decltype(0 + 0): " << typeid(decltype(0 + 0)).name() << "\n" 
     "int&&: " << typeid(int&&).name() << "\n"; 
    std::cout 
    << "ref_depth: int: " << ref_depth<int>::value << "\n" 
     "ref_depth: decltype(0 + 0): " << ref_depth<decltype(0 + 0)>::value << "\n" 
     "ref_depth: int&&: " << ref_depth<int&&>::value << "\n"; 

} 

輸出:

int: i 
decltype(0 + 0): i 
int&&: i 
ref_depth: int: 0 
ref_depth: decltype(0 + 0): 0 
ref_depth: int&&: 2 
+2

您能否在答案中包含代碼? (而不是總結代碼在答案中的結論並鏈接到一個完全不同的網站。) – 2011-05-08 03:21:24

+1

@Fred Nurk:我已經自由了。 – 2011-05-08 05:20:25

相關問題