Reputation: 16870
Using a range based for loop in C++11 with an existing variable, I would expect that variable to be filled with the value of the last iteration after the loop. However, I've gotten different results when I tested it.
Example:
#include <iostream>
#include <vector>
using namespace std;
int main() {
std::vector<int> v;
v.push_back(2);
v.push_back(43);
v.push_back(99);
int last = -50;
for (last : v)
std::cout << ":" << last << "\n";
std::cout << last;
return 0;
}
GCC-5.1 either automatically introduces a new variable or sets it back to the initial value, giving
:2
:43
:99
-50
I guess MSVC is just being MSVC again, but what about GCC here? Why is last
not 99
in the last line?
Given the definition by the standard, I would expect the behaviour I described in the first sentence.
{
auto && __range = range_expression ;
for (auto __begin = begin_expr, __end = end_expr;
__begin != __end; ++__begin) {
range_declaration = *__begin;
loop_statement
}
}
range_declaration
being last
and not int last
, this should modify the existing variable.
Upvotes: 28
Views: 4807
Reputation: 49986
Your code does not compile starting with gcc 6.1 (and for all clang versions):
main.cpp:12:8: error: range-based for loop requires type for loop variable
for (last : v)
^
auto &&
it looks like previous versions used auto implicitly here. The fact that you get -50 as last output is because for
introduces local scope for last, so after for
ends, last from outer scope was used.
I did a little digging and this was on purpose under gcc: N3994, terse range-for, which shortly is doing following:
A range-based for statement of the form
for ( for-range-identifier : for-range-initializer ) statement
is equivalent to
for ( auto&& for-range-identifier : for-range-initializer ) statement
then it didn`t make it to c++17 and was removed here:
https://gcc.gnu.org/viewcvs/gcc?view=revision&revision=229632
Upvotes: 10
Reputation: 66200
Your program doesn't compile with my g++ 4.9.2.
Compile with clang++ 3.5 (with a warning: "range-based for loop with implicit deduced type is a C++1z extension [-Wc++1z-extensions]")
But clang++ use different last
variables
With the following modified program
#include <iostream>
#include <vector>
using namespace std;
int main() {
std::vector<int> v;
v.push_back(2);
v.push_back(43);
v.push_back(99);
int last = -50;
std::cout << "extern last pointer: " << long(&last) << '\n';
for ( last : v)
{
std::cout << ": " << last << " ; pointer: " << long(&last) << '\n';
}
std::cout << "extern last pointer again: " << long(&last) << '\n';
std::cout << ": " << last << std::endl;
return 0;
}
I get the following output
extern last pointer: 140721376927168
: 2 ; pointer: 38101008
: 43 ; pointer: 38101012
: 99 ; pointer: 38101016
extern last pointer again: 140721376927168
: -50
Upvotes: 2
Reputation: 65620
GCC implemented standards proposal n3994, which suggests that for (elem : range)
be syntactic sugar for for (auto&& elem : range)
. This didn't make it into C++17, so the functionality has been removed from more recent versions of GCC.
The named variable used to iterate over the range must be a declaration according to [stmt.ranged]
, so your code shouldn't compile.
Upvotes: 23
Reputation: 459
according to the standard, a range based for loop is producing the same output as:
{
auto&& __range = expression;
for (auto __begin = begin-expression,
__end = end-expression;
__begin != __end;
++__begin)
{
declaration = *__begin;
statement
}
}
As you can see, the iteration variable __begin
is being defined in its own scope.
Why is last not 99 in the last line?
You have two variables called last
. One is in the scope of your main function and holds the value -50
. The second variable is defined in the scope of the range based for loop.
Inside the loop, printing the last
variable prints the one from the same scope (ie. from the range based for loop). After the loop however, printing last
will again print the variable from the same scope which is the one holding -50
Upvotes: 0