From [dcl.init.list]
The template
std::initializer_list
is not predefined; if the header <initializer_list> is not included prior to a use ofstd::initializer_list
— even an implicit use in which the type is not named — the program is ill-formed.
Since std::initializer_list
is special-cased by the compiler anyway, why is it not treated as a first-class syntax of the language?
My thoughts on some possibilities and its counter-arguments:
Namespace pollution
Could be solved just like std::size_t
, the inclusion of the header only introduces the identifier.
Note how auto sz = sizeof(0);
is well-formed even without the inclusion of any headers, as opposed to auto il = {1, 2, 3};
being ill-formed.
Compilation overhead
libstdc++ implementation of std::initializer_list
is literally less than 50 lines with no dependency on other headers. How big of overhead can that be?
typeid
(needingstd::type_info
), as well as<=>
in C++2a. – Unfruitful<=>
's discussion, a maintainer of a popular implementation stated that it is infeasible for their compiler to synthesize the entire class type result of<=>
. Synthesizing an entire class template would seem to be even more out of reach. – Journalismstd::vector<int> v{1, 2};
norauto il = {1, 2};
before C++11. The only possibility of ambiguity is aggregates, but the semantics are preserved there. – Bookmobilestd::cout
as a "first-class" part of C++ since it's UB to add your own stuff to that namespace, so the only possiblecout
that could be in there is theiostream
one. So why is usingstd::cout
invalid if you don't include<iostream>
? :-) – Empressstd::cout
has the semantics of a user defined object.std::initializer_list
doesn't, the language rules have ridiculously many special cases to accommodate it. – Bookmobiletypeid
and<=>
has a counter-example: there's no#include <lambda>
to useoperator()()
,operator+()
or copy constructor of[]{}
– Kosygin