Подтвердить что ты не робот

Что такое закрытый список фигурных скобок, если не список 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. Если это не то, что происходит, что такое список в фигурных скобках?

4b9b3361

Ответ 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