基于范围的for循环

时间:2017-01-22 21:39:01

标签: c++11 for-loop visual-c++

此代码在Visual Studio 2015更新3(以及此处:visual C++ compiler online中编译,而在我在线尝试的其他编译器(GCC和CLANG)中没有编译,给出重新声明错误

vector<int> v = {1,2,3};
for (auto i : v) {
  printf("%d ", i);
  int i = 99;
  printf("%d ", i);
}
  

输出:1 99 2 99 3 99

VS C ++在线编译器(版本:19.10.24903.0)警告:

  

警告C4456:'i'声明隐藏了之前的本地声明

C ++ 11规范中是否有一些空间允许两种实现都有效?

在我看来,VS2015正在为“auto i”创建一个范围,并为循环体创建一个内部范围。

正如同事建议的那样,添加一个额外的范围,在我测试的其他编译器中编译得很好(不是我想要这个,只是为了好奇):

vector<int> v = {1,2,3};
for (auto i : v) {{
  printf("%d ", i);
  int i = 99;
  printf("%d ", i);
}}

感谢

修改 好的,在阅读了另一个问题Redeclaration of variable in range-based for loops和“Angew”的答案之后,我相信VS实际上是正确的。

我在这里阅读:cpp reference

鉴于此语法描述:

for ( range_declaration : range_expression ) loop_statement

这相当于:

{
 auto && __range = range_expression ; 
 for (auto __begin = begin_expr, __end = end_expr; 
  __begin != __end; ++__begin) { 
    range_declaration = *__begin; 
    loop_statement
 } 
} 

我理解 loop_statement 实际上是我的整个块,包括括号,因此重新定义确实在内部块中,因此有效。

编辑2: 我的上一次编辑,以供将来参考,阅读传统的 for loop 语法与基于范围的类似情况(cpp for loop):

for ( init-statement condition(optional); iteration_expression(optional) ) statement

“上述语法产生的代码相当于:”

{
   init_statement 
   while ( condition ) { 
     statement 
     iteration_expression ; 
   }
}

回过头来看,我还可以解释/解析语句作为我的内部块,包括大括号,我至少期望这种行为符合我的编译器。但是所有编译器都会为传统的for循环重新声明错误而挽救。

2 个答案:

答案 0 :(得分:5)

N4606(C ++ 17 draft)3.3.3 basic.scope.block,第4节说

  

在...中声明的名称   初始化语句   ,   对于范围声明   ,并在   条件   的   如果   ,   而   ,   对于   ,和   开关   声明是本地的   如果   ,   而   ,   对于   , 要么   开关   声明(包括受控声明),   并且不得在该陈述的后续条件下或在最外面的区块中重新宣布(或者,对于   该   如果   声明,受控声明的任何最外面的块;见6.4

缩短:

  

在...... for-range-declaration ...中声明的名称是... for ...的本地名称,不得在该语句的后续条件中重新声明,也不得在最外面的块中重新声明

我读到这句话时说不应该允许。

答案 1 :(得分:0)

  

C ++ 11规范中是否有一些空间允许两种实现都有效?

除了一个例外,唯一的答案是否。

例外是全局变量,您可以使用范围操作符::来访问它们。否则,如果 shadow 外部作用域中的变量名称,则您将无法再访问它。