Reputation: 61
I studied that references always need to be initialzed. So why this code reported as an example of range based for, in my C++ book, should be correct?
#include <iostream>
#include <vector>
using namespace std;
int main ()
{
vector <int> v {0, 1, 2, 3} // should double each element of v,
// without writing it.
for (auto &r : v)
{
r *= 2;
}
return 0;
}
Thanks for all your answers, I know you're all skillful programmers... But some answers are still too advanced for me, so I'll choose the most intelligible for me. Thanks, again!
Upvotes: 1
Views: 205
Reputation: 254471
The reference is initialised in each iteration, to refer to each element of the vector.
This style of for-loop is roughly equivalent to one like
for (auto it = v.begin(); it != v.end(); ++it) {
auto &r = *it;
// your code goes here
}
where you can see that the reference is initialised.
Another answer quotes the full definition from the language standard, if you're interested in the gory details.
Upvotes: 1
Reputation: 310990
In the semantic description of the range based for statement there is written
for-range-declaration = *__begin;
Relative to your example this equivalent to
auto &r = *__begin;
that is that reference is always initialized.
Here is the complete semantic definition of the range fased for statement from the C++ Standard
{
auto && __range = range-init;
for ( auto __begin = begin-expr,
__end = end-expr;
__begin != __end;
++__begin ) {
for-range-declaration = *__begin;
statement
}
}
That is this statement
for ( for-range-declaration : expression ) statement
is semantically equivalent to the construction above.
For example if expression is an array named a with N elements then the loop will look like
for ( auto __begin = a, __end = a + N; __begin != __end; ++__begin )
{
auto &r = *__begin;
//...
}
Upvotes: 3
Reputation: 8284
I always like to think of
for (auto &r : v)
{
...
}
as equivalent to
std::for_each(std::begin(v),std::end(v),[&](auto &r)
{
...
});
note that the auto &r
in the lambda needs C++14.
edit: or mixing the definition in the standard from @VladfromMoscow and the answer from @JBL
for(
auto it = std::begin(v),
end = std::end(v);
it != end;
++it)
{
auto& r = *it;
//Loop code
}
Maybe that is easier for you to grasp than the description in the standard (although it's not as precise as the description in the standard).
Upvotes: 2
Reputation: 385174
The auto& r
component is not meant to represent an entire declaration; it only specifies the type and name of the element to generate on each iteration.
The initialisation is handled for you at the start of each iteration by the innards of range-for. That's the point! :)
Similarly, in the following, you do not assign values to x
on your own; it's done by the loop:
for (int x : v) {}
Upvotes: 0
Reputation: 12907
Because the semantics of the range-based for loop are roughly equivalent to the following (readable) code:
auto it = v.begin();
for(; it != v.end(); ++it){
auto& r = *it;
//Loop code
}
That is, the reference is declared and initialized it each time.
Upvotes: 0