Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What Is a Curly-Brace Enclosed List If Not an intializer_list?

I asked a question here: Lifetime Extension of a initializer_list return involving the non-functional code:

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

I believed the lambda was trying to return an intializer_list (that's bad, don't do that.) But I got a comment:

It's not an initializer_list, it's an initializer list. Two different things.

I just thought that any time you did a curly-braced list you were creating an intializer_list. If that's not what's happening, what is a list in curly-braces?

like image 983
Jonathan Mee Avatar asked Jun 07 '16 14:06

Jonathan Mee


People also ask

Which of the following will be enclosed within curly braces?

A compound statement is a sequence of zero or more statements enclosed within curly braces. Compound statements are frequently used in selection and loop statements.

What do you mean by curly braces?

Definition of curly brace : either one of the marks { or } that are used as a pair around words or items that are to be considered together.

What is an open curly brace?

An open curly bracket is { and a close curly bracket is } Curly brackets are used to mark what code is in a certain block. To type a curly bracket, hold down the SHIFT key and press the key that has [ and { on it. You can find that key on your keyboard directly to the right of P.

Is it necessary to use curly braces after the for statement?

Without curly brackets, you could accidentally write a semicolon after the IF-statements. The semicolon is a valid, empty statement, which will be "execute" instead of the actual (intended) one.


2 Answers

It is an braced-init-list. A braced-init-list existed before std::initializer_list and is used to initialize aggregates.

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

The above used a braced-init-list to initialize the array, no std::initializer_list is created. On the other hand when you do

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

foo is not an aggregate so the braced-init-list is used to create a std::initializer_list which is in turned passed to the constructor of foo that accepts a std::initializer_list.

A thing to note about a braced-init-list is that is has no type so special rules were developed for use with it and auto. It has the following behavior (since the adoption of 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 

And you can get more information on history of this behavior and why it was changed at: Why does auto x{3} deduce an initializer_list?

like image 174
NathanOliver Avatar answered Sep 20 '22 08:09

NathanOliver


There are three distinct, but related concepts here:

  1. braced-init-list: The grammatical rule associated with curly-brace-enclosed lists in certain contexts.

  2. Initializer list: The name for the braced-init-list initializer used in list-initialization.

  3. std::initializer_list: A class wrapping a temporary array which is created in some contexts involving braced-init-lists.

Some examples:

//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 }; 

You might want to read N3922, which changed some of the rules involving auto and std::initializer_list.

like image 21
TartanLlama Avatar answered Sep 22 '22 08:09

TartanLlama