I often use initializer lists and for-each loops to iterate through a small number of ad-hoc values, like so:
for (auto x : {1, 2, 6, 24, 120}) {
do_something(x);
}
I recently tried to write something similar, but with structured bindings and packed-together values instead:
for (auto[dx, dy] : {{-1, 0}, {1, 0}, {0, -1}, {0, 1}}) {
try_to_move(dx, dy); // nope! won’t compile
}
Unfortunately, this doesn’t compile. Clang tells me:
error: cannot use type ‘void’ as a range
In fact, even something like auto mylist = {{1, 2}, {3, 4}};
won’t compile.
This leaves me with two questions:
Is there an alternative syntax to accomplish what I want in a terse and readable manner?
Why doesn’t the type of auto mylist
get parsed as initializer_list<initializer_list<int>>
? Wouldn’t that work fine?
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 ofauto
with either a new invented type template parameter U or, if the initialization is copy-list-initialization, withstd::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} }) {
. . .
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With