C
To answer the first question, we can start with the second, which will make the reasons for the first more obvious.Construction (called http://en.cppreference.com/w/cpp/language/range-for , or for range based for (declaração : expressão) corpo
It is only syntactic sugar and is transformed to the following construction:{
auto && __range = expressão ;
auto __begin = begin_expr; // normalmente begin_expr é begin(__range)
auto __end = end_expr; // normalmente end_expr é end(__range)
for ( ; __begin != __end; ++__begin) {
declaração = *__begin;
corpo
}
}
Note that this transformation is conforming to /questions/tagged/c%2b%2b17 .This version of for works with any expression that can be iterated. In your example, std::vector can be iterated as it has the member functions std::vector::begin and std::vector::end, which return iterators to the beginning of the vector and to the end, respectively. For example:#include <cassert>
int main() {
std::vector<int> v{1, 2, 3};
int soma = 0;
for (int i : v)
soma += i;
assert(6 == soma);
}
If we just take the part of for from the above example, we see thatint i is the declaration,v is the expression andsoma += i; it is body.In the transformation (a little more simplified), we will have:{
auto __begin = begin(v);
auto __end = end(v);
for ( ; __begin != __end; ++__begin) {
int i = *__begin;
soma += i;
}
}
Note that the part int i = *__begin is where each element of the range (the vector v in this case) is assigned to the variable i. The body of for comes next.O for based on range, as said before, works with any interval. Therefore, any container that is possible to achieve an iterator from its beginning and end will work with this construction of for (e.g. arrays of fixed size, some standard library container, such as std::map, std::vector, std::array etc.If the concept iterator is not familiar, see it as an object that can traverse the elements of a container. For example, a pointer for the first element of the vector can be considered an iterator, because when we increment this pointer, we will gain access to the elements following that vector, until it reaches the end, which is a pointer for after the last element (meaning the arrival, or end of the iteration). In that case, __begin and __end would be such iterators, where __begin has access to the first element (and is incremented during the loop, to access the following elements) and __end represents the end of iteration. When __begin is equal to __end, means that the loop ended and all the elements were iterated.Returning to the first question, we see that now it is obvious why we declare vi as a reference. If we look at your example:for (auto &vi : v) {
vi *= fator;
}
We have auto &vi as declaration, v as expression and vi *= fator as corpo:{
auto __begin = begin(v);
auto __end = end(v);
for ( ; __begin != __end; ++__begin) {
auto &vi = *begin;
vi *= fator;
}
}
When we attribute the vector elements v in each iteration, we got the Reference for that element. If we had the declaration as just auto vi (or) double vi), we would be copying the element to the variable vi. Since the purpose is to modify the element, a copy would not work, we want written access to the element, so the reference is used.Attention., the use of as prefix of names are reserved by standardization. Do not write such names on your own, as they are used exactly to prevent user code from conflicting with standard library code, syntactic sugars or intrinsic compiler functions.