Identifier with the same name in both expression a

2019-04-18 17:11发布

问题:

Is it legal to declare a loop variable in a ranged-based for loop with the same name I use in the expression statement of the loop? I hope the example makes it clear.

#include <iostream>
#include <vector>

struct bar {
    std::vector<int> nums;
};

int main()
{
    bar b;
    b.nums = {1, 2, 3};

    for(int b : b.nums)
        std::cout << b << std::endl;   
}

gcc 4.8 gives an error while clang 3.2 allows it.

回答1:

From my reading of C++2011 6.5.4, your code of:

bar b;

for(int b : b.nums)
    std::cout << b << std::endl;

Should be converted to:

bar b;

{
   auto && __range = b.nums;
   for (auto __begin = __range.begin(), __end = __range.end(); __begin != __end; ++__begin ) {
       int b = *__begin;
       std::cout << b << std::endl;
   }
}

This to me means that clang is correct.



回答2:

Clang is right.

Paragraph 6.5.4/1 of the C++11 Standard defines the range-based for statement as follows:

For a range-based for statement of the form

for ( for-range-declaration : expression ) statement

let range-init be equivalent to the expression surrounded by parentheses

( expression )

and for a range-based for statement of the form

for ( for-range-declaration : braced-init-list ) statement

let range-init be equivalent to the braced-init-list. In each case, a range-based for statement is equivalent to

{
    auto && __range = range-init;
    for ( auto __begin = begin-expr,
          __end = end-expr;
          __begin != __end;
          ++__begin ) {
        for-range-declaration = *__begin;
        statement
    }
}

From the above, it is visible that variable b, which corresponds to the for-range-declaration, is declared inside a nested block statement, while the initializer range-init (which corresponds to b.nums) appears in the parent scope, where b should resolve to the object of type bar.



回答3:

For what it's worth, this bug has now been fixed on gcc trunk. :)