不,这实际上是正确的行为。
6.4 选择语句[stmt.select]
由条件中的声明引入的名称(由 thetype-specifier-seq
或条件的声明者引入)的范围从其声明点到由条件控制的子语句结束。如果名称在由条件控制的子语句的最外层块中重新声明,则重新声明该名称的声明格式不正确。[ 例子:
if (int x = f()) {
int x; // ill-formed, redeclaration of x
}
else {
int x; // ill-formed, redeclaration of x
}
—结束示例]
(强调我的)
这基本上意味着 的范围i
从条件开始,在if
-block 之后结束,其中else
-block 也是 -block 的一部分if
。
您对嵌套的第二个问题if
是基于(错误的)假设 anelse-if
是 introductory 的一部分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
-declaration 在 中可见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