Во-первых, у вас действительно есть два варианта одной вещи:
T x = { 1, 2, 3 };
T x{1, 2, 3};
Эти два действительно делают то же инициализацию с тем исключением, что первый является недействительным, если он выбирает explicit
конструктор. В противном случае они идентичны. Первая называется «копирование списка-инициализация», а вторая - «direct list-initialization».
Концепция состоит в том, что форма с =
присваивает «составное значение» - значение, состоящее из 3 целых чисел. И он инициализирует x
с этим значением. Для такой инициализации допускаются только конструкторы не explicit
. Концепция для x{1, 2, 3}
(без знака равенства) заключается в том, что вы инициализируете переменную . 3 значения - концептуально не составное значение, а 3 отдельных значения, которые вы получаете сразу. Вы могли бы сказать, что это «вызов конструктора» в самом общем смысле этого термина.
Другой инициализации вы показали действительно что-то совершенно отличается от двух предыдущих:
T x({1, 2, 3});
Это только вызывает constuctors из T
с {1, 2, 3}
в качестве аргумента. Он не выполняет никаких причудливых действий, таких как инициализация массива, если T
является массивом или инициализацией элементов структуры, если T
является агрегатной структурой/классом. Если T
не является классом, это объявление недействительно. Но если T
имеет конструктор копирования или перемещения, он может, в свою очередь, использовать этот конструктор для создания временного T
путем инициализации списка копий и привязать ссылочный параметр конструктора копирования/перемещения к этому временному. Я считаю, что вам не понадобится эта форма часто в реальном коде.
Все это записано в документах предложений комитета для списков инициализаторов. В этом случае, вы хотите взглянуть на Initializer Lists — Alternative Mechanism and Rationale, в разделе «Просмотреть программист инициализации видов»:
Мы наблюдали, что экспертные программисты, которые знают о разнице между авторскими инициализацией и direct- инициализация часто ошибочно полагает, что первая менее эффективна, чем последняя. (На практике, когда оба инициализация имеет смысл, они одинаково эффективны.)
Мы находим, напротив, что это более полезно думать об этих вещах в различных условиях:
- построении путем вызова конструктор (а «т е р-вызов»)
- построения путем передачи значения (а «преобразование»)
(Как это происходит, бывших соответствует «прямой инициализации», а второй «копировать - инициализация ", но Термины andard в не помогают программисту.)
Позже, они находят
Заметим, что так как мы лечить { ... }
в
X x = { ... };
как одно значение, оно не является эквивалент
X x{ ... };
, где { ... }
- список аргументов для вызова конструктора (мы подчеркиваем его, потому что он отличается от N2531).
Правила, изложенные в C++ 0x FDIS, несколько отличаются от представленных в этой статье, но обоснование, представленное в этой статье, сохраняется и реализуется в C++ 0x FDIS.
Хотя это хороший ответ, скажите, что они не добавили совершенно новый синтаксис для инициализации ** просто **, чтобы «исправить» наиболее неприятный синтаксический анализ: - /. –
Ну, очень приятно иметь единый синтаксис инициализации (или, я полагаю, это действительно здорово, у меня не было возможности использовать его еще: -P). Из-за различных досадных парсов (как 'T x()', так и его более досадного друга 'T x (T())'), круглые скобки не могут использоваться в качестве препинатора для равномерного синтаксиса инициализации. У брекетов нет этой проблемы. –
@Evan: есть причина, по которой это называется _uniform_ инициализацией. Потому что он работает везде одинаково. '{}' означает «инициализация» сейчас; в этом и есть идея. –