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
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 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
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
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?