Единая инициализация — важная и полезная функция C++11. Однако вы не можете просто использовать {}
везде, так как:
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(y) вызовет f(X) с помощью определяемого пользователем преобразования, и кто-то приходит с f(Y), который точно соответствует. Я думаю, было бы справедливо ожидать, что кто-то, кто использует {…}, вспомнит о возможности конструкторов списков инициализаторов. [выделено мной]
Я предполагаю, что ключ заключается в может быть, что означает, что вам не нужно использовать универсальную инициализацию. Правильно использовать {}
сложно, так как:
вам нужно проверить не только конструктор, который вы хотите вызвать, но и любой конструктор, принимающий
initializer_list
, который может победить (и, вероятно, выиграет) над ним;если вы пишете код, используя
{}
, а кто-то в будущем добавит конструкторstd::initializer_list
, ваш код может сломаться и сделать это молча.
Даже если у вас есть класс A
с конструкторами A(int, bool)
и A(std::initializer_list<double>)
, последний будет выбран вместо первого для A a{0, false};
(что, по-моему, безумие), поэтому мне действительно сложно использовать унифицированную инициализацию для классов которые имеют или могут иметь (требуются сверхспособности хрустального шара) initializer_list
конструкторов.
Тот факт, что ваш код может незаметно сломаться, меня очень беспокоит.
std::array
, возможно, требующая двух наборов фигурных скобок. Но я думаю, что это исправляется. - person juanchopanza   schedule 19.03.2014auto e{0, 0};
было ошибкой. Я также не думаю, что кто-то хотел бы, чтобы это рассматривалось как применение оператора запятой. Единственный разумный тип для этого —std::initializer_list<int>
(или что-то вродеint[]
). Но еслиauto e{(list of ints)};
должно быть разрешено какstd::initializer_list<int>
, аauto e{0};
находится в формеauto e{(list of ints)};
, то добавление определенных исключений на основе длины списка вызовет особые ненужные сложности. - person   schedule 19.03.2014auto d = {0}; // type of d is int
-- либо это неправильно, либо реализация GCC. GCC также делаетd
типаstd::initializer_list<int>
. - person   schedule 19.03.2014auto e{0,0}
было применением оператора запятой, аauto e{{0,0}}
выводилось вinitializer_list
. Просто для согласованности, посколькуdecltype(0,0)
выводит применение оператора запятой:decltype(0,0) a = 0
иauto a{0,0}; a = 0;
в настоящее время даже отдаленно не похожи. - person gnzlbg   schedule 19.03.2014auto a{0,0}
не использует оператор запятой? Возможно, они есть в Вавилонской библиотеке. - person juanchopanza   schedule 19.03.2014auto e = {0,0};
анализировалась как оператор, даже если ее нет вint e[] = {0,0};
, даже до того, какauto
преобразуется в конкретный тип? Последний не может измениться, это было бы огромной обратной несовместимостью. - person   schedule 19.03.2014auto e = {0,0}
однозначно является initializer_list,auto e{...}
IMO несовместим сdecltype
. Эти два случая являются редкостью для ИМО. Однако в контексте конструкторов, принимающих несколько аргументов, по сравнению с перегрузками, принимающими initializer_list, неожиданное может произойти незаметно (и IMO действительно случается). Я сделал акцент на том, что проблема заключается в том, какой векторный конструктор выбран. - person gnzlbg   schedule 19.03.2014auto e{...}
иauto e = {...}
выводили по-разному. Я думаю, что это также вызвало бы много путаницы. - person   schedule 19.03.2014{}
для обозначения юниформ-инициализации иstd::initializer_lists
. - person gnzlbg   schedule 19.03.2014auto e{...}
иauto e = {...}
выводят по-разному, см. N3922, который был включен в рабочий документ в прошлом месяце. - person Jonathan Wakely   schedule 19.03.2014decltype(0,0) a = 0
иauto a{0,0}; a = 0;
в настоящее время даже отдаленно не похожи ... и это хорошо.decltype
сообщает вам тип выражения, список-инициализаторов — это список выражений, а не одно выражение. Запятые в списках не используют оператор запятой (рассмотрите списки параметров функций, списки аргументов шаблонов, списки ctor-initializer и т. д. и т. д.) - person Jonathan Wakely   schedule 19.03.2014X a{...};
создаетX
, передавая...
своему конструктору, поэтому очевидным было бы использованиеX a{ {...} }
для передачи одного списка инициализаторов (X a{ {...}, {...} }
для передачи двух списков инициализаторов,...). ЯрлыкX a{...}
, где...
выводится как список инициализаторов, кажется, доставляет больше головной боли, чем того стоит. - person gnzlbg   schedule 19.03.2014