Во-первых, у вас действительно есть два варианта одной вещи:
T x = { 1, 2, 3 };
T x{1, 2, 3};
Эти два действительно выполняют одну и ту же инициализацию , за исключением того, что первый недопустим, если он выбирает explicit
конструктор . В остальном они идентичны. Первый называется «копировать список-инициализация», а второй - «прямая список-инициализация».
Концепция заключается в том, что для формы с =
назначается «составное значение» - значение, состоящее из 3-х целых. И он инициализирует x
с этим значением. Для такой инициализации должны быть разрешены только не-1011 * конструкторы. Концепция для x{1, 2, 3}
(без знака равенства) заключается в том, что вы инициализируете переменную значениями 3 - концептуально не составное значение, а 3 отдельных значения, которые вы получаете одновременно. Вы могли бы сказать, что это «вызов конструктора» в самом общем смысле этого термина.
Другая инициализация, которую вы показали, действительно отличается от двух предыдущих:
T x({1, 2, 3});
Он вызывает только конструкторы T
с {1, 2, 3}
в качестве аргумента. Он не делает ничего необычного, например, инициализирует массив, если T
является массивом, или инициализирует элементы структуры, если T
является агрегатной структурой / классом. Если T
не является классом, это объявление недопустимо. Но если T
имеет конструктор копирования или перемещения, то он, в свою очередь, может использовать этот конструктор для создания временного T
путем инициализации списка копирования и связать ссылочный параметр конструктора копирования / перемещения с этим временным. Я считаю, что вам не понадобится эта форма часто в реальном коде.
Все это записано в предложениях комитета по спискам инициализаторов. В этом случае вам нужно взглянуть на Списки инициализаторов - альтернативный механизм и обоснование , в разделе «Взгляд программиста на виды инициализации»:
Мы заметили, что опытные программисты, которые знают о разнице между
инициализация и прямая инициализация часто ошибочно полагают, что первое менее эффективно, чем второе. (На практике, когда обе инициализации имеют смысл, они одинаково эффективны.)
Наоборот, мы находим, что более полезно думать об этих вещах в разных терминах:
- конструирование путем вызова конструктора ("ctor-call")
- построение путем передачи значения («преобразования»)
(Как оказалось, первое соответствует «прямой инициализации», а второе «копировать
инициализация ", но условия стандарта не помогают программисту.)
Позже они находят
Обратите внимание, что поскольку мы рассматриваем { ... }
в
X x = { ... };
как одно значение, оно не эквивалентно
X x{ ... };
где { ... }
- список аргументов для вызова конструктора (мы подчеркиваем это, потому что он не похож на N2531).
Правила, изложенные в C ++ 0x FDIS, немного отличаются от представленных в этом документе, но обоснование, представленное в этом документе, сохраняется и реализуется в C ++ 0x FDIS.