So I am aware that braces in code can mean more than just an initializer_list
: What Is a Curly-Brace Enclosed List If Not an intializer_list?
But what should they default to?
For example, say that I define an overloaded function:
void foo(const initializer_list<int>& row_vector) { cout << size(row_vector) << "x1 - FIRST\n"; }
void foo(const initializer_list<initializer_list<int>>& matrix) { cout << size(matrix) << 'x' << size(*begin(matrix)) << " - SECOND\n"; }
If I call foo({ 1, 2, 3 })
the 1st will obviously be called. And if I call foo({ { 1, 2, 3 }, { 4, 5, 6 }, { 7, 8, 9 } })
the 2nd will obviously be called.
But what if I call:
foo({ { 1 }, { 2 }, { 3 } })
Are those nested braces int
-initializers or initializer_list<int>
intializers? gcc says it's ambiguous But if you take that code and run it on http://webcompiler.cloudapp.net/ Visual Studio says it's just constructing an initializer_list<int>
. Who's right? Should there be a default here?
The rule is in [over.ics.list]:
In both your overloads, the worst conversion necessary is the identity conversion. So we have two implicit conversion sequences with rank identity. There is a rule in [over.match.best] which prefers a list-initialization of a
std::initializer_list<X>
over alternatives (sostd::initializer_list<int>
is preferred toint
for{1}
), but there nothing to suggest that this rule should apply recursively.Since there's nothing to disambiguate the two conversion sequences, the call is ambiguous. gcc and clang are correct to reject.