2014-03-19 20 views
7

統一初始化是一個重要且有用的C++ 11功能。但是,你不能只用{}無處不在,因爲:爲什麼不是雙花括號語法首選構造函數採用std :: initializer_list

std::vector<int> a(10, 0); // 10 elements of value zero 
std::vector<int> b({10, 0}); // 2 elements of value 10 and 0 respectively 
std::vector<int> c{10, 0}; // 2 elements of value 10 and 0 respectively 
std::vector<int> d = {10, 0}; // 2 elements of value 10 and 0 respectively 

auto e(0); // deduced type is int 
auto f = 0; // deduced type is int 
auto g{0}; // deduced type is std::initializer_list<int> 
auto h = {0}; // deduced type is std::initializer_list<int> 

注意到在例如集合初始化std::arrays需要使用{{}},在我看來,與整個問題,其矢量構造函數將選擇通過要求{{}}本來是可以避免調用構造函數採取std::initializer_list

std::vector<int> i{10, 0}; // 10 elements of value zero 
std::vector<int> j{{10, 0}}; // 2 elements of value 10 and 0 respectively 
std::vector<int> k = {10, 0}; // 2 elements of value 10 and 0 respectively 

auto l{0}; // deduced type is int 
auto m{{0}}; // deduced type is std::initializer_list<int> 
auto n = {0}; // deduced type is std::initializer_list<int> 

我敢肯定這是討論過的,所以反對這個的原因是什麼?來自標準提案的報價/鏈接是首選答案。

更新。 - 有在N2532點,指出:

(3)只發生短初始化列表的可能討厭不確定性的情況下[...]

(5)爲什麼要語言規則力的程序員誰想要簡潔 和模糊控制(完美的理由)寫更多 請程序員誰更喜歡(爲了完美的原因)更多 顯式 - 可以嗎?

[...]

假設一個程序員期望F(X)被調用。 f(Y) 如何「劫持」呼叫? (4)假設X沒有初始化列表構造函數,但是Y沒有。在 這種情況下,給予初始化列表構造函數的優先級青睞劫持程序(記住我們假定程序員以某種方式預計f(X)被調用)。這類似於某人希望使用用戶定義的轉換調用f(X),並且有人來到 以及完全匹配的f(Y)。 我認爲這將是公平的 期望有人誰使用{...}將記住 初始化器列表構造函數的可能性。 [重點煤礦]

我想關鍵在於可以,這意味着你不必使用統一的初始化。使用{}正確是困難的,因爲:

  • 你不僅要檢查你想打電話,但也爲任何構造服用initializer_list可能贏得(可能會)在它的構造函數;

  • 如果在未來使用{}有人編寫代碼將一個std::initializer_list構造你的代碼可能會破壞和這樣做默默

即使你有一類A與構造A(int, bool)A(std::initializer_list<double>),後者將在前者被選擇爲A a{0, false};(其中IMO是堅果),所以我覺得它真的很難用統一的初始化在具有或可能有(需要水晶球超級大國)initializer_list構造函數。

事實上,你的代碼可以默默地打破我很多擔心。

+0

我不確定你試圖解決哪個「問題」。你只是展示了一種不同的做事方式。我看到的唯一「問題」是'std :: array',可能需要兩組大括號。但我認爲這是正在解決的問題。 – juanchopanza

+2

我試圖解決的問題是找出爲什麼這種不同的做事方式不是標準化的(目前的做法)。特別是,我可能需要這個決定背後的原因或反對它的好例子才能得到滿足。 – gnzlbg

+0

我不認爲有人會想'auto e {0,0};'是一個錯誤。我也不認爲有人會希望它被視爲逗號運算符的應用程序。唯一明智的類型是'std :: initializer_list '(或類似'int []'的東西)。但是,如果'auto e {(int列表)};'被解析爲'std :: initializer_list ',並且'auto e {0};'的格式爲'auto e {(list of int)} ;',那麼它會導致特殊的不必要的複雜性,以便根據列表的長度添加特定的例外。 – hvd

回答

8

這裏是斯特勞斯已經就此說:

統一和通用的沒有設計只是一個第四選擇。它被設計爲初始化語法,並且遺憾的是不適用於所有遺留代碼,尤其是vector。如果我今天設計了vector,您將不得不說出類似vector<int> {Count{9}};的數字來計算。

並回應問題「是問題向量還是{-init-syntax}?」

它的矢量設計:如果我今天設計vector,你將不得不這樣說:vector<int> {Count{9}};得到一個計數。

更常見的問題是,若干語義不同的相同類型的參數最終導致混淆,特別是如果它們可能出現混亂。例如:

vector<int> v(7,2); // 7 (a count) element with the value 2 
3

(這是不是一個真正的答案,只是一個什麼,我已經想過這個問題上的討論。)

我想我會喜歡的編譯器給在不明確的情況下發出警告,建議開發人員使用({ })(如果他們確實需要initializer_list)或()(如果他們不需要)。如果MostVexingParse存在風險,請附加警告! - 也許推薦(())來避免這種情況?

(這下面的「故事」很可能不是基於的功能是如何制定正確的歷史年表,但它是我所理解的編譯器目前的規則)

在我們有構造函數的開頭:

type t (...); 

然後我們必須讓{給文字收集用於構造函數(也是其他地方)的想法。

type t ({...}); 

...以及一個新的initializer_list類型在構造函數中匹配這個。

然後,我們被允許以避免最讓人頭疼的解析與{ }更換()

type t { ... }; 
type t { {...} }; 

到目前爲止,一切都很好。對語言的純粹擴展。

最後,「爭議」除了是,當編譯器看到{ ... }(作爲構造函數),它會首先嚐試回落上(...)之前重寫爲({ ... })(調用initializer_list如果存在的話)。我認爲如果兩種選擇都被認爲是同樣好的,並且如果兩者都有可能會出現警告或錯誤,我寧願選擇。

相關問題