簡體   English   中英

為什么我不能使用統一初始化初始化初始化列表中的引用?

[英]Why can't I initialize a reference in an initializer list with uniform initialization?

也就是說,為什么這樣:

struct S {};

struct T
{
    T(S& s) : s{s} {}

    S& s;
};

int main()
{
    S s;
    T t{s};
}

給我一個GCC 4.7的編譯器錯誤:

test.cpp: In constructor 'T::T(S&)':
test.cpp:5:18: error: invalid initialization of non-const reference of type 'S&' from an rvalue of type '<brace-enclosed initializer list>'

要修復錯誤,我必須將s{s}更改為s(s) 這不會打破統一初始化的統一性嗎?

編輯 :我試過clang,clang接受它,所以也許這是一個GCC錯誤?

是的,這是一個錯誤 這是一個新的東西,並在2012年2月的工作文件中投票( 鏈接 )。

根據FDIS批准的C ++ 11標准, Nicol Bolas提出了一個很好的觀點,即gcc實際上是符合標准的編譯器,因為工作文件的更改是在此之后做出的。

我認為這是編譯器中的錯誤。 通過列表初始化處理引用初始化的兩段是(在n3337中):

§8.5.4/ 3

列表初始化對象或類型T的引用定義如下:

  • 否則,如果初始化列表具有E類型的單個元素且T不是引用類型或其引用類型與E引用相關,則從該元素初始化對象或引用; 如果需要縮小轉換(見下文)將元素轉換為T,則程序格式不正確。

  • 否則,如果T是引用類型,則由T引用的類型的prvalue臨時值被列表初始化,並且引用綁定到該臨時值。 [注意:像往常一樣,如果引用類型是非const類型的左值引用,則綁定將失敗並且程序格式錯誤。 - 結束說明]

編譯器似乎應用了最后一段,當它應該應用第一段時,因為引用相關被定義為

8.5.3 / 4

給定類型“cv1 T1”和“cv2 T2”,如果T1與T2的類型相同,則“cv1 T1”與“cv2 T2”相關,或者T1是T2的基類。

在問題的情況下,參數的類型和大括號初始化列表中的初始化程序完全相同,這意味着初始化應該是有效的。


在FDIS草案中,等效段落的順序相反。 這意味着FDIS草案(n3290)不允許* lvalue * s的括號列表初始化 另一方面,閱讀文本似乎很明顯,它是標准中的錯誤 ,並且意圖是n3337的順序:

  • 否則,如果T是引用類型,則由T引用的類型的prvalue臨時值被列表初始化,並且引用綁定到該臨時值。

  • 否則,如果初始化列表具有單個元素,則從該元素初始化對象或引用 ; 如果需要縮小轉換(見下文)將元素轉換為T,則程序格式不正確。

該文檔中的順序意味着因為所有引用類型都由第一個子句處理,所以在下一段中提及引用是沒有意義的。

(注意:我寫這個答案的原因是自原始問題以來有2年的后見之明;並且將評論中的一些信息放入實際答案中以便可以搜索到)。


當然,初始化類型S&的引用並且還具有類型S&的引用應該直接綁定。

問題是C ++ 11標准中的缺陷並由DR1288解決。 更正的文本出現在C ++ 14中。

委員會澄清說,更正后的文本是針對C ++ 11的,因此“符合標准的編譯器”應該實現更正后的版本。

g ++ 4.8遵循C ++ 11標准的已發布文本; 然而,一旦發現這個問題,g ++ 4.9實現了更正版本,即使使用-std=c++11開關也是如此。

注意,問題不僅限於構造函數初始化列表,例如: S s; S &t{s}; S s; S &t{s}; 在g ++ 4.8中不起作用, S s; S &t = s; S &u { t };也不起作用S s; S &t = s; S &u { t }; S s; S &t = s; S &u { t };

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM