Let's look at the following simple range based for loop:
int a = 5, b = 6;
for (auto & i : {a, b})
{
std::cout << i << std::endl; // Works as expected.
i = 3; // Error!
}
gcc complains about assignment of read-only reference 'i', implying that the range based for loop used with an initializer list implicitly adds a const qualifier to the reference, totally unprovoked.
In
int a = 5, b = 6;
for (auto & i : {a, b})
You have that {a, b} is an std::initialiser_list of two elements, a and b, in which the values of a and b are copied. Now, std::initializer_list only provides constant iterators to its elements, because initializer_lists are immutable, so you cannot bind the value to non-const lvalue references.
One option would be to pass pointers instead, which would make the pointers themselves constant, but not the value they point to:
for (auto& i : {&a, &b})
*i = 0;
Live demo
Another alternative would be to use an std::reference_wrapper, but that would still required a call to .get() or an explicit cast static_cast<int&> in this case:
for (auto& i : {std::ref(a), std::ref(b)})
i.get() = 0;
Live demo
Considering that std::reference_wrapper has an implicit conversion operator to T&, I wouldn't be surprised if in some other context you would be able to automatically trigger an implicit conversion (as opposed to calling .get()).
Also note that {a, b} is not a range of numbers from a to b, it's really just those two numbers. So with int a = 0, b = 10 you would not have [0, 10] but the list of 0 followed by 10.
If you want to have "proper" ranges, I recommend you take a look at Boost.Range.
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