条件声明的变量范围

Seb*_*ach 9 c++ scope

一些重构导致一段代码导致我进入这个最小的测试用例:

int main () {
    if (int i=1) {
        /* IF-BLOCK */
    } else {
        throw i;
    }
}
Run Code Online (Sandbox Code Playgroud)

编译好了.但是,我一直认为这i只是可见的IF-BLOCK,但似乎并非如此.这是编译器错误吗?

另外,为什么以下工作呢?

int main () {
    if (int i=1) {
    } else if (int i=2) {
    } else {
        throw i;
    }
}
Run Code Online (Sandbox Code Playgroud)

注意第二个if"重新声明" i.另一个编译错误?

Seb*_*ach 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
}
Run Code Online (Sandbox Code Playgroud)

- 结束例子]

(强调我的)

这基本上意味着范围i从条件开始,并在if-block 之后结束,其中else-block也是-block的一部分if.

嵌套的第二个问题if是基于(错误的)假设,即a else-if是介绍的一部分if,但事实并非如此.这if (int i=2)第一个的身体else!

     if (int i=1)
          |
         / \
        /   \
       /     \
      /       \
     /         \
   if-block   else
               |
           if(int i=2)
             /    \
            /      \
           /        \
       if-block   throw i
Run Code Online (Sandbox Code Playgroud)

这又意味着什么:

int main () {
    if (int i=1) {    
    } else if (1) {
        throw (i+2);
    } else {
        throw i;
    }
}
Run Code Online (Sandbox Code Playgroud)

此代码有效,因为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;
    }
}
Run Code Online (Sandbox Code Playgroud)

总而言之,不要惊慌:使用上一个语句中找到的模式编写标记符或解析器或某些东西仍然有效,这里的相关新知识是条件中的任何声明都跨越整个if树,但可以覆盖任何嵌套的if.

另外,请确保以下内容仍然无效(即使它在旧编译器中有效):

if (int i=0) {}
std::cout << i; // nope, not valid
Run Code Online (Sandbox Code Playgroud)