此代码在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循环重新声明错误而挽救。
答案 0 :(得分:5)
N4606(C ++ 17 draft)3.3.3 basic.scope.block,第4节说
在...中声明的名称 初始化语句 , 对于范围声明 ,并在 条件 的 如果 , 而 , 对于 ,和 开关 声明是本地的 如果 , 而 , 对于 , 要么 开关 声明(包括受控声明), 并且不得在该陈述的后续条件下或在最外面的区块中重新宣布(或者,对于 该 如果 声明,受控声明的任何最外面的块;见6.4
缩短:
在...... for-range-declaration ...中声明的名称是... for ...的本地名称,不得在该语句的后续条件中重新声明,也不得在最外面的块中重新声明
我读到这句话时说不应该允许。
答案 1 :(得分:0)
C ++ 11规范中是否有一些空间允许两种实现都有效?
除了一个例外,唯一的答案是否。
例外是全局变量,您可以使用范围操作符::
来访问它们。否则,如果 shadow 外部作用域中的变量名称,则您将无法再访问它。