条件中声明的变量的作用域

Scope of variable declared in condition

本文关键字:变量 作用域 声明 条件      更新时间:2023-10-16

一些重构导致了一段代码,这段代码将我引向了这个最小的测试用例:

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。另一个编译器错误?

不,这实际上是正确的行为。

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-块的一部分。

嵌套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树,但可以在任何嵌套的if中被覆盖。

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

if (int i=0) {}
std::cout << i; // nope, not valid