Ответ 1
С++ 03
Инициализация списка
В С++ 03 вы можете использовать только инициализацию списка для агрегатов (С++ 03 [dcl.init.aggr]) и скалярные (С++ 03 [dcl.init]/13) типы:
int i = { 0 };
POD pod = { 0, 1, 2 };
Назначение списка
Вы не можете использовать "назначение списка" в любом месте на С++ 03. Грамматика, показанная в [expr.ass]/1, не позволяет скопировать список справа от присваивания.
С++ 11
Инициализация списка
В С++ 11 вы можете использовать инициализацию списка почти везде, где вы можете создать переменную (см. [dcl.init] в С++ 11 и [dcl.init.list]/1, в которой перечислены контексты, инициализация разрешена) например
struct Base { };
struct Class : Base
{
int mem{ 0 }; // init non-static data member
Class(int i)
: Base{} // init base class
, mem{i} // init member
{
int j{i}; // init local var
int k = int{0}; // init temporary
f( { 1 } ); // init function arg
int* p = new int{1}; // new init
// int k(int()); // most vexing parse, declares function
int k{ int{} }; // ok, declares variable
int i[4]{ 1,2,3,4 }; // init array
}
Class f(int i)
{
return { i }; // init return value
}
};
Class c{1}; // init global var
Большинство инициализаций выше объявляют int
или массив int
, но тот же синтаксис может использоваться для вызова конструктора для типа класса (например, две строки, которые строят переменную Class
)
Как и в любом контексте, где вы можете инициализировать переменную, инициализация списка также хорошо взаимодействует с другой новой функцией С++ 11: шаблона класса std::initializer_list
. Конструктор, который принимает аргумент std::initializer_list
, может быть передан произвольно длинный список значений, который конструктор может перебирать через begin()
и end()
функции-члены из std::initializer_list
. Основное преимущество этой новой функции заключается в том, что она позволяет инициализировать контейнер с набором элементов, например. vector<int> v{ 0, 1, 2, 3, 4, 5 }
вместо того, чтобы конструировать контейнер, а затем вставлять значения.
Инициализация списка также может использоваться для элементов в списке с расширенным списком, позволяя вложенную инициализацию списка, например. Map m{ {a, b}, {c, d} }
, а не Map m{ Map::value_type(a, b), Map::value_type(c, d) }
Единственная инициализация списка времени не делает правильную вещь, когда вы пытаетесь построить тип класса, вызывая конструктор, если класс имеет другой конструктор, принимающий std::initializer_list
, поскольку инициализация списка всегда будет предпочтительнее принимать конструктор a std::initializer_list
eg
// attempts to create vector of 5 elements, [1,1,1,1,1]
// but actually creates a vector with two elements, [5,1]
std::vector<int> v{ 5, 1 };
Это не вызывает конструктор vector(size_type, const int&)
, а не вызывает конструктор vector(initializer_list<int>)
.
Назначение списка
В С++ 11 вы можете использовать "list-assign"
- при назначении скалярному типу, если в списке бит-init есть один элемент, который можно конвертировать (без сужения) в тип переменной (см. [expr.ass]/9)
-
когда левый операнд присваивания является типом класса с определяемым пользователем оператором присваивания, и в этом случае бит-init-list используется для инициализации аргумента оператора (см. [expr.ass]/9). Это включает в себя как случаи, такие как
operator=(std::initializer_list<T>)
, где элементы списка braced-init-list в правом операнде конвертируются вT
, например. дляstd::vector<int> v
выше,v = { 1, 2, 3 }
заменит содержимое контейнера на [1,2,3], и когда список braced-init может быть неявно преобразован в тип аргумента оператора, через подходящий конструктор, напримерstruct A { int i; int j; }; struct B { B& operator=(const A&); }; int main() { B b; b = { 0, 1 }; }
В последней строке
main
бит-init-list будет неявно преобразован во временныйA
, тогда оператор присваиванияB
будет вызван с таким временным аргументом.