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_list
s 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