2016-10-03 232 views
9

我正在爲此提交GCC錯誤,但我寧願仔細檢查一下。括號初始化與括號問題

考慮以下方案:

#include <utility> 
template<typename T, typename A> 
void F(A&& a) { T(std::forward<A>(a)); } // Note:() syntax. 
int main() { int i; F<int&>(i); } 

和:

#include <utility> 
template<typename T, typename A> 
void F(A&& a) { T{std::forward<A>(a)}; } // Note: {} syntax. 
int main() { int i; F<int&>(i); } 

最新鏘和MSVC的編譯器都接受的方案。 GCC 5及更高版本接受第一個程序,但拒絕第二個程序,聲稱invalid cast of an rvalue expression of type 'int' to type 'int&'

這是一個海灣合作委員會的bug?或者這是上述情況下T{}T()之間的差異(並因此是Clang和MSVC中的錯誤)?

編輯:

這個問題可以縮小到以下簡單摘錄:

int i; (int&){i}; 

int i; (int&)(i); 
+0

你甚至可以定義並初始化一個未命名的左值引用嗎?反正這個錯誤似乎不正確。 – krzaq

+0

@krzaq:我不明白爲什麼不。另外,我在'noexcept'表達式中出現了這個錯誤,所以我想了解表達式中的情況。 – alecov

+4

這是[核心問題1288](http://wg21.link/cwg1288)。海灣合作委員會應該正在實施其決議,但也許並沒有完全解決。 –

回答

6

有兩個不同的問題:

  • 該標準不清楚T{x}應該爲參考類型T做什麼。目前[expr.type.conv]/1表示它創建了一個類型爲T的prvalue,這對於參考類型是無意義的。這是core issue 1521
  • 理智的事情是可能有T{x}參考類型T做大致T __tmp{x};,然後得到的static_cast<T>(__tmp)等效(因此x值對右值參考T和左值用於左值參考T)。然而,正如公佈的C++ 11搞砸了引用列表初始化的規範,使得它總是創建一個臨時的。結果是int i; int &r{i};未能編譯,因爲它會嘗試將r綁定到i的臨時副本,這顯然是無稽之談。這由core issue 1288修復,其分辨率GCC應該實現,但它看起來像來自錯誤消息,它不完全固定。