首页 > 解决方案 > switch 语句中 case 标签后语句中的重新声明

问题描述

考虑这个例子

#include <iostream>
int main(){
    switch(int a  = 1){  //#condition
        case 1: switch(int a = 2){}
        case 2: switch(int a = 2){}
    }
}

为什么a在这个例子中重新声明的格式正确?
根据以下规则:

basic.scope.block#3

在 init-statement、for-range-declaration 以及 if、while、for 和 switch 语句的条件中声明的名称对于 if、while、for 或 switch 语句(包括受控语句)是局部的,并且不得在该语句的后续条件中或受控语句的最外层块(或者,对于 if 语句,任何最外层块)中重新声明

IIUC,无论是声明中的声明switch(int a = 2){}还是switch(int a = 2){}都在受控语句的最外层,这是一个复合语句。

作为对比:

#include <iostream>
int main(){
    switch(int a  = 1){  //#condition
        case 1: int a = 2;
    }
}

aafter的重新声明case 1是不正确的,因为它是在该语句的最外面的块中重新声明的。

阐明

根据stmt.block,块是复合语句的别名。所以上面的规则完全是关于block的,它与范围无关。该规则相当于:

不得在受控语句的最外层复合语句中重新声明。

所以,我在这里无法理解的是,由于 inner 的条件switch和 first 的最外层块之间没有任何块switch,怎么能说 inner 的条件switch不在 outer 的最外层块中switch

    switch(int a  = 1){  <-  outermost block of the primary `switch`
        case 1: switch(int a = 2 /*there's no any block contains this condition*/){}
    }

作为对比:

    switch(int a  = 1){  <-  outermost block of the primary `switch`
        case 1: {  /* here exists a block between `int a = 2` and outermost block of the primary `switch`, so the condition definitely not in the outermost block*/
             switch(int a = 2 ){} 
        }
    }

我错过的标准中是否有任何关于类似于stmt.while#2的转换的规则,这将使条件包含在发明的块(复合语句)中?

标签: c++language-lawyer

解决方案


真正的问题是这里的含义{}分隔之间的任何东西switch当然都在那个“最外层块”中,但是“最外层”的使用清楚地暗示我们不应该考虑(也)在嵌套块内的程序部分。达到这种解释的最简单方法是将“in”读作“<strong>directly in”,这与“在命名空间中声明的函数”通常不包括该命名空间中的类的成员函数相同。然后嵌套的条件switch被免除,因为其中的声明不直接在任何块中。

P1787R6于 2020 年 11 月通过,它通过重写 [basic.scope.block] 来明确指出与子语句相关的单数范围,与 [stmt.while]/2 中的转换无关。


推荐阅读