Die Variable wird im äußersten Block einer Unteranweisung neu deklariert

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

Der obige Code kann sowohl in gcc als auch in clang kompiliert werden . Gemäß den einschlägigen Regeln sollte dieser Code jedoch fehlerhaft sein. Die Regeln sind:

stmt.stmt # 3

Ein Name, der durch eine Deklaration in einer Bedingung eingeführt wird (entweder durch den Deklarationsspezifizierer-seq oder den Deklarator der Bedingung eingeführt), ist vom Deklarationspunkt bis zum Ende der von der Bedingung kontrollierten Unteraussagen im Geltungsbereich. Wenn der Name im äußersten Block einer von der Bedingung gesteuerten Unteranweisung erneut deklariert wird , ist die Deklaration, die den Namen erneut deklariert, falsch.

Ist die if-Anweisung, die der elsenicht folgt, nicht eine von der Bedingung gesteuerte Unteranweisung? (dh nur die Bedingung bei #conditionAusführung falsewird ausgeführt, wenn die if-Anweisung elseausgeführt wird). Warum kann eine Deklaration, die den Namen im äußersten Block einer solchen Unteranweisung neu deklariert, als wohlgeformter Code betrachtet werden?

Vielleicht gibt es in diesen Versionsregeln einige Argumente für den Ausdruck "von der Bedingung kontrollierte Unteraussage" n4659, aber eine solche Idee ist im neuesten Entwurf offensichtlich klar.

stmt.stmt # stmt.pre-2

Eine Unteranweisung einer Anweisung ist eine der folgenden:
für eine Auswahlanweisung eine ihrer Anweisungen (aber nicht ihre init-Anweisung)

Das bedeutet, dass die Anweisung nach elseeine Unteranweisung der primären if-statementist. Dann lauten die nächsten Regeln: stmt.stmt # stmt.pre-5

Ein Name, der in einer Auswahlanweisung oder Iterationsanweisung außerhalb einer Unteranweisung eingefügt wird, ist vom Deklarationspunkt bis zum Ende der Unteranweisungen der Anweisung gültig. Ein solcher Name kann im äußersten Block einer der Unteranweisungen nicht erneut deklariert werden

Die Regel besagt offensichtlich, dass wir nicht denselben Namen wie den im äußersten Block dieser Unteranweisungen deklarierten Namen erneut deklarieren können. Ich bin also gespannt, ob ich diese Regeln missverstanden habe oder ob der Entwurf einige Mängel aufweist.

Antworten

2 cigien Nov 06 2020 at 09:39

Die Anweisung in stmt.stmt # stmt.pre-5 lautet explizit:

[Anmerkung 2: Ein Name, der in eine Auswahlanweisung oder Iterationsanweisung außerhalb einer Unteranweisung eingefügt wird, ist vom Deklarationspunkt bis zum Ende der Unteranweisungen der Anweisung gültig. Ein solcher Name kann im äußersten Block einer der Unteranweisungen ([basic.scope.block]) nicht erneut deklariert werden . - Endnote]

Der Schlüsselbegriff hier ist der äußerste Block, der in stmt.block # 1 definiert ist :

Eine zusammengesetzte Anweisung (auch als Block bezeichnet) gruppiert eine Folge von Anweisungen zu einer einzigen Anweisung.

Zusammengesetzte Aussage:

{Anweisung-seq opt}

...

Eine zusammengesetzte Anweisung definiert einen Blockbereich.

So stmt.stmt # stmt.pre-5 ist im Wesentlichen zu sagen:

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

aber

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

Die gleichen Regeln gelten in Ihrem Beispiel für den Block, der durch die verschachtelte ifAnweisung eingeführt wird.

3 AsteroidsWithWings Nov 06 2020 at 09:07

Nein.

Ihnen fehlt der durch die elseUnteranweisung eingeführte Blockbereich:

[stmt.selected.general/2]: Die Unteranweisung in einer Auswahlanweisung (jede Unteranweisung in elseForm der ifAnweisung) definiert implizit einen Blockbereich ([basic.scope]). Wenn die Unteranweisung in einer Auswahlanweisung eine einzelne Anweisung und keine zusammengesetzte Anweisung ist, ist es so, als ob sie als zusammengesetzte Anweisung umgeschrieben wurde, die die ursprüngliche Unteranweisung enthält. [..]

dh dein Code ist wirklich:

#include <iostream>

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

Daher ist der Block, den Sie betrachten (der von den verschachtelten eingeführte if), nicht der "äußerste" Block. Obwohl aes sich innerhalb dieses Blocks im Geltungsbereich befindet, kann es schattiert werden.

Dies bedeutet, dass Sie ein aInneres nicht als "nackt" deklarieren könnenelse , dh Folgendes ist schlecht geformt:

#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) {
*/