So I can do this:
for(const auto i : { 13, 42 }) cout << i << ' ';
But I can't do this:
copy_n(cbegin({ 13, 42 }), 2, ostream_iterator<int>(cout, " "));
It gives me the error:
error: no matching function for call to
cbegin(<brace-enclosed initializer list>)
What is it about the for
-statement that allows this but not the cbegin
function?
Edit:
It appears that the problem is that my initializer_list
isn't being treated as an initializer_list
, because if I do this it works:
copy_n(cbegin(initializer_list<int>{ 13, 42 }), 2, ostream_iterator<int>(cout, " "));
{ 13, 42 }
is braced initializer list. It doesn't have a type, it is just a list and it depends on how it used as how it gets treated. std::cbegin
is defined like
template< class C >
constexpr auto cbegin( const C& c ) -> decltype(std::begin(c));
and since the braced initializer list doesn't have a type, the template type deduction fails. In the ranged based for loop we use the list different. A range based for loop expands to
{
init-statement
auto && __range = range_expression ;
auto __begin = begin_expr ;
auto __end = end_expr ;
for ( ; __begin != __end; ++__begin) {
range_declaration = *__begin;
loop_statement
}
}
with auto && __range = range_expression ;
becoming auto && __range = { 13, 42 }
. Now auto
follows template type deduction except that since the committee decide that auto
should work with braced initializer list, auto
will deduce { 13, 42 }
to a std::initiaizer_list<int>
since the list contains only int
s.
If you change the code to
copy_n(begin({ 13, 42 }), 2, ostream_iterator<int>(cout, " "));
even though std::begin
is defined like cbegin
and takes a template type, <initializer_list>
introduces an overload that takes a std::initializer_list
and that will get called instead.