Что такое список в фигурных скобках, если не intializer_list?

Я задал вопрос здесь: Lifetime Расширение возврата initializer_list с участием нефункционального кода:

const auto foo = [](const auto& a, const auto& b, const auto& c) { return {a, b, c}; };

Я верил, что лямбда пытается вернуть intializer_list (это плохо, не делай этого.) Но я получил комментарий:

Это не initializer_listЭто список инициализатора. Две разные вещи.

Я просто думал, что каждый раз, когда вы составляли фигурный список, вы создавали intializer_list, Если это не то, что происходит, что такое список в фигурных скобках?

4 ответа

Решение

Здесь есть три различных, но связанных понятия:

  1. braced-init-list: Грамматическое правило, связанное со списками в фигурных скобках в определенных контекстах.

  2. Список инициализатора: имя для инициализатора braced-init-list, используемого в инициализации списка.

  3. std::initializer_list: Класс, обертывающий временный массив, который создается в некоторых контекстах с использованием скобок-init-list s.

Некоторые примеры:

//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,

Это ограниченный список инициализации. Предварительный список фигурных скобок существовал до std::initializer_list и используется для инициализации агрегатов.

int arr[] = {1,2,3,4,5};

Для инициализации массива выше использовался список фигурных скобок, нет std::initializer_list создано. С другой стороны, когда вы делаете

std::vector<int> foo = {1,2,3,4,5};

foo не является агрегатом, поэтому для создания std::initializer_list который в свою очередь передается конструктору foo который принимает std::initializer_list,

Следует отметить, что тип braced-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?

Я просто думал, что каждый раз, когда вы составляли фигурный список, вы создавали intializer_list,

Это не правильно.

Если это не то, что происходит, что такое список в фигурных скобках?

struct Foo {int a; int b;};
Foo f = {10, 20};

{10, 20} часть не initializer_list, Это просто синтаксическая форма для использования списка объектов для создания другого объекта.

int a[] = {10, 20, 30};

Еще раз, это синтаксическая форма для создания массива.

Название для синтаксической формы braced-init-list,

У вас есть две разные вещи при использовании {}

  1. Тип std::initializer_list<T> где значения могут быть неявно преобразованы в T
  2. Тип, который можно инициализировать значениями списка.

Первый тип вызывает однородный список, а второй - нет. В следующем примере:

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
Другие вопросы по тегам