Идентификатор с тем же именем в выражении и декларации диапазона для
Является ли законным объявлять переменную цикла в цикле, основанном на диапазоне, с тем же именем, которое я использую в выражении оператора цикла? Надеюсь, что этот пример дает понять.
#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.:)