Что такое закрытый список фигурных скобок, если не список intializer_list?
Я задал вопрос здесь: Lifetime Расширение возврата initializer_list с использованием нефункционального кода:
const auto foo = [](const auto& a, const auto& b, const auto& c) { return {a, b, c}; };
Я полагал, что лямбда пыталась вернуть intializer_list
(это плохо, не делайте этого). Но я получил comment:
Это не initializer_list
, это список инициализаторов. Две разные вещи.
Я просто подумал, что всякий раз, когда вы делали фигурный список, вы создавали intializer_list
. Если это не то, что происходит, что такое список в фигурных скобках?
Ответы
Ответ 1
Здесь есть три различных, но связанных понятия:
-
braced-init-list: грамматическое правило, связанное с вложенными в фигурные скобки списками в определенных контекстах.
-
Список инициализаторов: имя инициализатора списка бит-инициализации, используемого в инициализации списка.
-
std::initializer_list
: класс, который переносит временный массив, который создается в некоторых контекстах с использованием списков braced-init.
Некоторые примеры:
//a braced-init-list and initializer list,
//but doesn't create a std::initializer_list
int a {4};
//a braced-init-list and initializer list,
//creates a std::initializer_list
std::vector b {1, 2, 3};
//a braced-init-list and initializer list,
//does not create a std::initializer_list (aggregate initialization)
int c[] = {1, 2, 3};
//d is a std::initializer_list created from an initializer list
std::initializer_list d {1, 2, 3};
//e is std::initializer_list<int>
auto e = { 4 };
//f used to be a std::initializer_list<int>, but is now int after N3922
auto f { 4 };
Возможно, вы захотите прочитать N3922, который изменил некоторые правила, связанные с auto
и std::initializer_list
.
Ответ 2
Это бит-init-list. Перед std::initializer_list
существовал бит-init-список и используется для инициализировать агрегаты.
int arr[] = {1,2,3,4,5};
В приведенном выше примере был использован бит-init-list для инициализации массива, no std::initializer_list
. С другой стороны, когда вы делаете
std::vector<int> foo = {1,2,3,4,5};
foo
не является агрегированным, поэтому бит-init-list используется для создания std::initializer_list
, который передается в конструктор foo
, который принимает std::initializer_list
.
Замечание о скобках-init-list состоит в том, что у него нет типа, поэтому для него были разработаны специальные правила и auto
. Он имеет следующее поведение (с момента принятия N3922)
auto x1 = { 1, 2 }; // decltype(x1) is std::initializer_list<int>
auto x2 = { 1, 2.0 }; // error: cannot deduce element type
auto x3{ 1, 2 }; // error: not a single element
auto x4 = { 3 }; // decltype(x4) is std::initializer_list<int>
auto x5{ 3 }; // decltype(x5) is int
И вы можете получить дополнительную информацию об истории этого поведения и о том, почему он был изменен: Почему auto x {3} выводит список initializer_list?
Ответ 3
Я просто подумал, что всякий раз, когда вы делали фигурный скопированный список, вы создавали intializer_list
.
Это неверно.
Если это не то, что происходит, что такое список в фигурных скобках?
struct Foo {int a; int b;};
Foo f = {10, 20};
Часть {10, 20}
не является initializer_list
. Это просто синтаксическая форма для использования списка объектов для создания другого объекта.
int a[] = {10, 20, 30};
Еще раз, это синтаксическая форма для создания массива.
Название синтаксической формы braced-init-list
.
Ответ 4
У вас есть две разные вещи при использовании {}
- A Тип
std::initializer_list<T>
, где значения могут быть неявно преобразованы в T
- Тип, который можно инициализировать со значениями списка.
Первый тип заставляет однородный список, а второй тип - нет. В следующем примере:
struct S{
int a;
string b
};
void f1( S s );
void f2( int i );
void f3( std::initializer_list<int> l );
f1( {1, "zhen"} ); // construct a temporal S
f2( {1} ); // construct a temporal int
f3( {1,2,3} ); // construct a temporal list of ints
Функции f1 и f2 используют первый тип, а f3 - второй тип. Вы должны знать, что если есть двусмысленность, предпочитается std:: initializer_list. Например:
void f( S s );
void f( int i );
void f( std::initializer_list<int> l );
f( {1, "zhen"} ); // calls with struct S
f( {1} ); // calls with int list with one element
f( {1,2,3} ); // calls with int list with three elements