Идентификатор с тем же именем в выражении и декларации диапазона для

Является ли законным объявлять переменную цикла в цикле, основанном на диапазоне, с тем же именем, которое я использую в выражении оператора цикла? Надеюсь, что этот пример дает понять.

#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 дает ошибку, в то время как clang 3.2 позволяет это.

Ответы

Ответ 1

Из моего чтения С++ 2011 6.5.4 ваш код:

bar b;

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

Необходимо преобразовать в:

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;
   }
}

Это для меня означает, что clang верен.

Ответ 2

Кланг прав.

Параграф 6.5.4/1 стандарта С++ 11 определяет оператор for на основе диапазона:

Для диапазона для выражения формы

for ( for-range-declaration : expression ) statement

пусть range-init будет эквивалентен выражению, окруженному круглыми скобками

( expression )

и для определения диапазона для формы

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

пусть range-init будет эквивалентен списку с привязкой к init-init. В каждом случае оператор, основанный на диапазоне, эквивалентен к

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

Из вышесказанного видно, что переменная b, которая соответствует for-range-declaration, объявляется внутри оператора вложенного блока, тогда как инициализатор range-init (который соответствует b.nums) появляется в родительском scope, где b должен быть разрешен к объекту типа bar.

Ответ 3

Для чего это стоит, эта ошибка теперь исправлена ​​на gcc trunk.:)