2015-02-24 47 views
9

我最近看到一些基於SFINAE代碼看起來像這樣:爲什麼我們不能在未評估的上下文中使用括號初始值設定項?

template <typename T> 
auto test(T &myclass) -> decltype(myclass.f(), void()) 
{ 
    // do something here, don't return anything (void) 
} 

基本上上面的函數使用SFINAE拒絕沒有f()作爲一個成員函數T類型的所有參數。 SFINAE發生在decltype中,我們有兩個由逗號運算符分隔的表達式。如果第一個表達式不能被評估,SFINAE會踢入並拒絕超載。如果可以評估表達式,則由於逗號運算符,void正在從該函數返回。

據我明白,void()「構建」一個void對象處於未評估上下文(是的,這是合法的),然後將其由decltype拾取所以void是該函數的返回類型。

我的問題是:爲什麼我們不能用void{}代替?它有沒有在未評估的上下文中「構造」void對象的相同效果?我的編譯器(一個或多個)(克++ /鐺++)不接受void{}代碼

error: compound literal of non-object type 'void'(克++ 4.9 /克++ 5)

error: illegal initializer type 'void'(鏗鏘聲++ 3.5)

+0

它是一個函數聲明嗎?我認爲不能在'decltype'中使用函數聲明,但只能使用函數名稱,但我可能會被最令人頭痛的解析再次咬傷;)3分鐘後:我確實非常確定它不是MVP,因爲'decltype(int( int))x;'被拒絕,但'decltype(int())x;'是有效的,'x'的類型是'int'。 – vsoftco 2015-02-24 05:10:00

回答

8

這是一個表達式。 [expr.type.conv]/P2-3:

表達T(),其中T簡單型說明符類型名稱說明符用於非陣列的完整對象類型或 (可能是cv-qualified)void類型,創建 指定類型的值,其值是通過值初始化 (8.5)T類型的對象生成的值;沒有爲 void()案件進行初始化。 [:... - 注完]後跟一個 支撐,初始化列表

同樣,簡單類型說明符類型名稱說明符創建的臨時對象指定類型 直接列表初始化(8.5.4)用指定的braced-init-list, 其值爲臨時對象爲prvalue。

您不能創建void類型的臨時對象。 void()是一個特殊的例外,它允許您創建一個void prvalue。

+0

有趣......所以'T()'是一個prvalue,而'T {}'(幾乎)是一個xvalue,如果我理解正確 – vsoftco 2015-02-24 05:25:51

+0

@vsoftco「它的值是臨時對象作爲prvalue」。 – 2015-02-24 05:27:11

+0

我必須在早上重新閱讀;) – vsoftco 2015-02-24 05:28:20

相關問題