一些重构导致一段代码导致我进入这个最小的测试用例:
int main () {
if (int i=1) {
/* IF-BLOCK */
} else {
throw i;
}
}
编译好。但是,我始终认为i
仅对IF-BLOCK
可见,但似乎并非如此。这是编译器错误吗?
另外,为什么以下工作?
int main () {
if (int i=1) {
} else if (int i=2) {
} else {
throw i;
}
}
注意第二个if
“重新声明”i
。另一个编译错误?
答案 0 :(得分:15)
不,这实际上是正确的行为。
6.4选择语句[stmt.select]
由声明引入的名称(由
type-specifier-seq
或条件的声明者引入)从声明的范围到结束的范围的子语句受控制 由条件。 如果名称在由受控制的子语句的最外面块中重新声明 条件,重新声明名称的声明 格式错误。 [例如:if (int x = f()) { int x; // ill-formed, redeclaration of x } else { int x; // ill-formed, redeclaration of x }
- 结束示例]
(强调我的)
这基本上意味着i
的范围始于条件,并在if
- 块之后结束,其中else
- 块是if
的一部分-block也是。
嵌套if
的第二个问题是基于(错误的)假设else-if
是介绍性if
的一部分,但事实并非如此。 if (int i=2)
是第一个else
的主体!
if (int i=1)
|
/ \
/ \
/ \
/ \
/ \
if-block else
|
if(int i=2)
/ \
/ \
/ \
if-block throw i
这又意味着什么:
int main () {
if (int i=1) {
} else if (1) {
throw (i+2);
} else {
throw i;
}
}
此代码有效,因为i
- 声明在throw (i+2);
中可见,但它仍然有效隐藏第一个i
,因为在嵌套作用域中,名称可以覆盖:
int main () {
if (int i=1) {
} else if (int i=2) {
throw (i+2); // now refers to `int i=2`
} else {
throw i;
}
}
总而言之,不要惊慌:使用上一个语句中找到的模式编写标记符或解析器或某些东西仍然有效,这里的相关新知识是条件中的任何声明都跨越整个if
-tree,但可以在任何嵌套的if
中覆盖。
另外,请确保以下内容仍然无效(即使它在旧编译器中有效):
if (int i=0) {}
std::cout << i; // nope, not valid