Что такое список в фигурных скобках, если не 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 ответа
Здесь есть три различных, но связанных понятия:
braced-init-list: Грамматическое правило, связанное со списками в фигурных скобках в определенных контекстах.
Список инициализатора: имя для инициализатора braced-init-list, используемого в инициализации списка.
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
,
У вас есть две разные вещи при использовании {}
- Тип
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