Why doesn’t the type of auto mylist get parsed as initializer_list<initializer_list<int>>
? Wouldn’t that work fine?
The reason is that simply no-one proposed it yet.
The handy syntax auto x = {1, 2, 6, 24, 120};
comes from proposal N3912 which was adopted into C++17 (see also N3922).
The deduction process is outlined in [dcl.type.auto.deduct]/4:
If the placeholder is the auto
type-specifier, the deduced type T' replacing T is determined using the rules for template argument deduction. Obtain P from T by replacing the occurrences of auto
with either a new invented type template parameter U or, if the initialization is copy-list-initialization, with std::initializer_list<U>
. Deduce a value for U using the rules of template argument deduction from a function call, where P is a function template parameter type and the corresponding argument is e. If the deduction fails, the declaration is ill-formed.
Since type deduction in a hypothetical function call f({1, 2})
would fail, so too is the nested braced-init-list deduction auto x = { {1, 2}, {3, 4} };
also impossible.
I guess the same trick could be applied to a deduction from a function call, which would make nested initializer_list
deduction possible.
So a follow-up proposal is welcome.
Is there an alternative syntax to accomplish what I want in a terse and readable manner?
You could define a good old multidimensional array:
int lst[][2] = { {1, 2}, {3, 4}, {5, 6}, {7, 8} };
for (auto [x, y] : lst) {
. . .
}
Or as suggested in the comments, give the first pair a type to help the deduction:
for (auto [x, y] : { std::pair{1, 2}, {3, 4}, {5, 6}, {7, 8} }) {
. . .
}