While reading about a different topic I came across a weird behaviour, at least to me.
This whole thought originated from the special interactions between auto
and braces. If you write something like:
auto A = { 1, 2, 3 }
the compiler will deduce A
to be a std::initializer_list
. The weird thing is that a similar rule applies not only to auto
, where there can be special reasons for it, but also to other things.
If you write the following:
template<typename T>
void f(std::vector<T> Vector)
{
// do something
}
you can't of course call it in this way:
f({ 1, 2, 3});
even though a std::vector
can be braced initialized. However, if you substitute the std::vector
with std::initializer_list
, the call works and the compiler will properly deduce int
as the type T
. The more interesting thing is, however, that in the former case you need to #include <vector>
, in the latter you don't need to #include <initializer_list>
. This made me think and after a test I realized somehow std::initializer_list
don't need its own header, so it is in some way part of the "base" features.
Moreover, for everything to make sense, std::initializer_list
should be to standard objects in more or less the same way lambdas are to callable objects (in the strictest meaning, that is an object with a operator()
). In other words, unnamed braced definitions should default to std::initializer_list
just like lambdas are (mostly) unnamed callable objects.
Is this reasoning correct? Moreover, can this behaviour be changed and, if so, how?
UPDATE: the header for initializer_list
was found to be included transitively from iostream
(really weird). However, the question remains: why the call works for std::initializer_list
and not for std::vector
?