在子语句的最外层块中重新声明的变量

The variable redeclared in the outermost block of a substatement

#include <iostream>
int main(){
  int b = 2;
  if(int a = 0){  // #condition
  }else if(b == 2){
    int a;  //#1
  }
}

以上代码在gcc和clang中都可以compiled。但是,根据相关规则的说法,这段代码应该是病式的。规则是:

stmt.stmt#3

A name introduced by a declaration in a condition (either introduced by the decl-specifier-seq or the declarator of the condition) is in scope from its point of declaration until the end of the substatements controlled by the condition. If the name is redeclared in the outermost block of a substatement controlled by the condition, the declaration that redeclares the name is ill-formed.

else 后面的 if 语句不是由条件控制的子语句吗? (即只有 #condition 处的条件被执行为 false 才会执行 else 之后的 if 语句)。那么,为什么在这种子语句的最外层块中重新声明名称的声明可以被视为格式正确的代码?

也许n4659版本的规则中对“由条件控制的子语句”这一短语有一些争论,但是,这样的想法在最新的草案中显然很明确。

stmt.stmt#stmt.pre-2

A substatement of a statement is one of the following:
for a selection-statement, any of its statements (but not its init-statement)

这意味着 else 之后的语句是主 if-statement 的子语句,那么接下来的规则是: stmt.stmt#stmt.pre-5

A name introduced in a selection-statement or iteration-statement outside of any substatement is in scope from its point of declaration until the end of the statement's substatements. Such a name cannot be redeclared in the outermost block of any of the substatements

规则显然是说我们不能在这些子语句的最外层块中重新声明与条件中声明的名称相同的名称。所以,我想知道是我误解了这些规则还是草案中存在一些缺陷?

没有

您缺少 else 子语句引入的块作用域:

[stmt.selected.general/2]: The substatement in a selection-statement (each substatement, in the else form of the if statement) implicitly defines a block scope ([basic.scope]). If the substatement in a selection-statement is a single statement and not a compound-statement, it is as if it was rewritten to be a compound-statement containing the original substatement. [..]

即你的代码真的是:

#include <iostream>

int main()
{
  int b = 2;
  if (int a = 0) {
  }
  else {
    if (b == 2) {
       int a;
    }
  }
}

因此,您正在查看的块(由嵌套 if 引入的块)不是所讨论的“最外层”块。因此,虽然 a 在该块的范围内,但它可以被隐藏。

这个确实意思是you can't declare an a inside a "naked" else,即下面是ill-formed:

#include <iostream>

int main()
{
  int b = 2;
  if (int a = 0) {
  }
  else {
    int a;
  }
}

/*
prog.cpp: In function ‘int main()’:
prog.cpp:9:9: error: redeclaration of ‘int a’
     int a;
         ^
prog.cpp:6:11: note: ‘int a’ previously declared here
   if (int a = 0) {
*/

stmt.stmt#stmt.pre-5中的语句明确表示:

[Note 2: A name introduced in a selection-statement or iteration-statement outside of any substatement is in scope from its point of declaration until the end of the statement's substatements. Such a name cannot be redeclared in the outermost block of any of the substatements ([basic.scope.block]). — end note]

这里的关键词是outermost block,定义在stmt.block#1:

A compound statement (also known as a block) groups a sequence of statements into a single statement.

compound-statement:

{ statement-seq opt }

...

一个复合语句定义一个块作用域。

所以 stmt.stmt#stmt.pre-5 本质上是在说:

if (int a = 0) 
{  // outermost block
  int a;  // so ill-formed  
} 

但是

if (int a = 0) 
{  // outermost block 
 {  // inner block
   int a;  // so well-formed 
 }  
} 

相同的规则适用于嵌套 if 语句引入的块的示例。