変数をswitchステートメントで宣言できないのはなぜですか?


945

私はいつもこれを疑問に思っていました-なぜswitchステートメントのcaseラベルの後に変数を宣言できないのですか?C ++では、ほとんどどこでも変数を宣言できます(そして、最初の使用に近い変数を宣言することは明らかに良いことです)が、以下はまだ機能しません。

switch (val)  
{  
case VAL:  
  // This won't work
  int newVal = 42;  
  break;
case ANOTHER_VAL:  
  ...
  break;
}  

上記は私に次のエラー(MSC)を与えます:

「newVal」の初期化は「case」ラベルによってスキップされます

これは他の言語でも制限があるようです。なぜこれがそのような問題なのですか?


10
C BNF文法に基づく説明については、 stackoverflow.com
questions / 1180550 / weird

ここでは、 switchステートメントとラベル(ABC :)全般についての非常に優れた資料を示します。
Etherealone 2012

4
変数を宣言するのではなく、switchステートメントで初期化できないのはなぜでしょうか。変数を宣言するだけで、MSVCで警告のみが表示されます。
ZoomIn

回答:


1144

Case文は単なるラベルです。これは、コンパイラがこれをラベルへの直接ジャンプとして解釈することを意味します。C ++では、ここでの問題はスコープの1つです。中括弧は、switchステートメント内のすべてのものとしてスコープを定義します。これは、初期化をスキップするコードにさらにジャンプするスコープが残っていることを意味します。

これを処理する正しい方法は、そのcaseステートメントに固有のスコープを定義し、その中で変数を定義することです。

switch (val)
{   
case VAL:  
{
  // This will work
  int newVal = 42;  
  break;
}
case ANOTHER_VAL:  
...
break;
}

94
新しいスコープを開くことに関連して-コードの可読性と一貫性を優先します。昔は、自動的に「余分な」スタックフレームを取得していたかもしれませんが、今では、まともな最適化コンパイラーには当てはまりません。
トールジェフ

10
私はジェフに同意します。ほとんどの人が使用しているインデントスタイルのため、switchステートメントを読むときにスコープを "想定"するのは非常に簡単です。私自身のスタイルは、1行より長い場合は常に各ケース/デフォルトの新しいスコープを開くことです。
入札

39
workmad3-新しい変数を宣言しないと、新しいスタックフレームを生成するC ++コンパイラを見つけることができますか?少し心配しましたが、G ++ 3.1、Visual C ++ 7、Intel C ++ 8のいずれも、変数を宣言しない新しいスコープのコードを生成しません。
クリスジェファーソン

10
@ workmad3新しい中括弧ブロックを入力して、新しいスタックフレームはありませんstackoverflow.com/questions/2759371/...
MTVS

3
@TallJefあなたが何を言っているのかわからない。メソッドに入るときに、メソッドのすべてのスタックスペース割り当てられていないコンパイラに40年間出会ったことはありません
ローンの侯爵

333

この質問元々[C]と[C ++]のタグが同時に付けられていました。元のコードは、CとC ++の両方で実際に無効ですが、まったく別の無関係な理由によります。

  • C ++では、case ANOTHER_VAL:ラベルはnewValその初期化をバイパスして変数のスコープにジャンプするため、このコードは無効です。自動オブジェクトの初期化をバイパスするジャンプは、C ++では無効です。問題のこちら側は、ほとんどの回答で正しく対処されています。

  • ただし、C言語では、変数の初期化をバイパスしてもエラーにはなりません。初期化を超えて変数のスコープにジャンプすることは、Cでは合法です。これは単に、変数が初期化されていないままであることを意味します。元のコードは、まったく異なる理由でCでコンパイルされません。case VAL:元のコードのラベルは変数の宣言に添付されていますnewVal。C言語では、宣言はステートメントではありません。ラベルを付けることはできません。そして、これがこのコードがCコードとして解釈されるときにエラーを引き起こすものです。

    switch (val)  
    {  
    case VAL:             /* <- C error is here */
      int newVal = 42;  
      break;
    case ANOTHER_VAL:     /* <- C++ error is here */
      ...
      break;
    }

余分な{}ブロックを追加すると、C ++とCの両方の問題が修正されます。C ++側では、のスコープを制限し、そのスコープにジャンプしないnewValことを確認してcase ANOTHER_VAL:、C ++の問題を排除します。C側では、extra {}によって複合ステートメントが導入され、case VAL:ラベルがステートメントに適用されるようになり、Cの問題が解消されます。

  • Cの場合、問題はがなくても簡単に解決できます{}case VAL:ラベルの後に空のステートメントを追加するだけで、コードが有効になります

    switch (val)  
    {  
    case VAL:;            /* Now it works in C! */
      int newVal = 42;  
      break;
    case ANOTHER_VAL:  
      ...
      break;
    }

    現在はCの観点からは有効ですが、C ++の観点からは無効のままです。

  • 対称的に、C ++の場合、問題はがなくても簡単に解決できます{}。変数宣言から初期化子を削除するだけで、コードが有効になります

    switch (val)  
    {  
    case VAL: 
      int newVal;
      newVal = 42;  
      break;
    case ANOTHER_VAL:     /* Now it works in C++! */
      ...
      break;
    }

    現在はC ++の観点からは有効ですが、Cの観点からは無効のままです。


4
@AnT:C ++を修正したものがCに適用できない理由を理解しています。ただし、最初の初期化をスキップするというC ++の問題がどのように修正されるのか理解できません。newValそれがジャンプするときの宣言と割り当てをまだスキップしませんANOTHER_VALか?
legends2k

13
@ legends2k:はい、まだスキップします。ただし、「問題を修正する」とは、C ++コンパイラエラーを修正することを意味します。C ++では、初期化子を使用してスカラー宣言をスキップすることは違法ですが、初期化子を使用せずにスカラー宣言をスキップしても問題ありません。でcase ANOTHER_VAL:ポイント変数newVal見えるが、不定値です。
AnT 2015年

3
魅力的です。§A9.3: Compound StatementK&R C(第2版)を読んだ後、この質問を見つけました。エントリは、複合文の技術的定義であるに言及しています{declaration-list[opt] statement-list[opt]}。私は宣言文だと思っていたので、混乱し、私はそれを見て、すぐにこの問題、格差が明らかになり、実際に言っ例見つかっ破るプログラムを。もう1つの解決策(Cの場合)は、labeled-statementが満たされるよう、宣言のに別のステートメント(おそらくnullステートメント?)を置くことだと思います。
Braden Best

おっと、私が提案したnullステートメントのソリューションがすでにあなたの答えに含まれていることに気づきました。じゃあ心配しないで。
Braden Best

3
空のステートメントを追加する修正は、C99以降でのみ機能することに注意してください。C89では、変数はそれらを囲むブロックの先頭で宣言する必要があります。
Arthur Tacca

136

OK。これを明確にするためだけに、宣言とは関係ありません。「初期化の飛び越し」にのみ関連しています(ISO C ++ '03 6.7 / 3)

ここでの投稿の多くは、宣言を飛び越えると変数が「宣言されない」可能性があることを述べています。本当じゃない。PODオブジェクトは、初期化子なしで宣言できますが、値は不確定になります。例えば:

switch (i)
{
   case 0:
     int j; // 'j' has indeterminate value
     j = 0; // 'j' initialized to 0, but this statement
            // is jumped when 'i == 1'
     break;
   case 1:
     ++j;   // 'j' is in scope here - but it has an indeterminate value
     break;
}

オブジェクトが非PODまたは集約の場合、コンパイラーは暗黙的に初期化子を追加するため、そのような宣言を飛び越すことはできません。

class A {
public:
  A ();
};

switch (i)  // Error - jumping over initialization of 'A'
{
   case 0:
     A j;   // Compiler implicitly calls default constructor
     break;
   case 1:
     break;
}

この制限は、switchステートメントに限定されません。'goto'を使用して初期化を飛び越えることもエラーです。

goto LABEL;    // Error jumping over initialization
int j = 0; 
LABEL:
  ;

ちょっとした雑学は、これはC ++とCの違いだということです。Cでは、初期化を飛び越えてもエラーではありません。

他の人が述べたように、解決策はネストされたブロックを追加して、変数の寿命を個々のケースラベルに制限することです。


2
「初期化の飛び越しエラー」??? 私のGCCではありません。ラベルの下のjを使用すると、「jは使用されている可能性があります」という警告が表示されることがありますが、エラーは発生しません。ただし、切り替えの場合はエラーがあります(弱い警告ではなくハードエラー)。
メッキー2010

9
@Mecki:C ++では違法です。ISO C ++ '03-6.7 / 3: "...自動ストレージ期間を持つローカル変数がスコープ内にないポイントから、スコープ内にあるポイントにジャンプするプログラムは、変数がPODタイプでない限り、形式が正しくありません(3.9)そして、イニシャライザ(8.5)なしで宣言されています。」
Richard Corden

1
はい、しかしそれはCでは違法ではありません(少なくともgccはそうではないと言っています)。jは初期化されていません(乱数があります)が、コンパイラはそれをコンパイルします。ただし、switchステートメントの場合、コンパイラーはそれをコンパイルすることもできず、goto / labelケースとswitchケースの違いを確認できません。
Mecki

8
@Mecki:一般に、単一のコンパイラー動作は、言語によって実際に許可されていることを必ずしも反映するわけではありません。C'90とC'99の両方を確認しました。どちらの規格にも、switchステートメントに初期化ジャンプの例が含まれています。
Richard Corden、2010

38

switchステートメント全体が同じスコープ内にあります。それを回避するには、次のようにします。

switch (val)
{
    case VAL:
    {
        // This **will** work
        int newVal = 42;
    }
    break;

    case ANOTHER_VAL:
      ...
    break;
}

括弧に注意してください


30

すべての回答といくつかの調査を読んだ後、いくつかのことがわかります。

Case statements are only 'labels'

Cでは、仕様に従って、

§6.8.1ラベル付きステートメント:

labeled-statement:
    identifier : statement
    case constant-expression : statement
    default : statement

Cでは、「ラベル付き宣言」を許可する句はありません。言語の一部ではありません。

そう

case 1: int x=10;
        printf(" x is %d",x);
break;

これはコンパイルされません。http://codepad.org/YiyLQTYwを参照してください。GCCがエラーを出している:

label can only be a part of statement and declaration is not a statement

でも

  case 1: int x;
          x=10;
            printf(" x is %d",x);
    break;

これもコンパイルされません。http://codepad.org/BXnRD3buを参照してください。ここでも同じエラーが発生します。


C ++では、仕様に従って、

ラベル付き宣言は許可されていますが、ラベル付き初期化は許可されていません。

http://codepad.org/ZmQ0IyDGを参照してください


そのような状態への解決策は2つです

  1. {}を使用して新しいスコープを使用する

    case 1:
           {
               int x=10;
               printf(" x is %d", x);
           }
    break;
  2. または、ラベル付きのダミーステートメントを使用します

    case 1: ;
               int x=10;
               printf(" x is %d",x);
    break;
  3. switch()の前に変数を宣言し、条件を満たしている場合は、caseステートメントで異なる値で初期化します。

    main()
    {
        int x;   // Declare before
        switch(a)
        {
        case 1: x=10;
            break;
    
        case 2: x=20;
            break;
        }
    }

switchステートメントでさらにいくつかのこと

ラベルの一部ではないスイッチ内のステートメントは決して実行しないでください。

switch(a)
{
    printf("This will never print"); // This will never executed

    case 1:
        printf(" 1");
        break;

    default:
        break;
}

http://codepad.org/PA1quYX3を参照してください


2
Cの問題を正しく説明しました。しかし、C ++でラベル付けされた初期化が許可されていないという主張は完全に真実ではありません。C ++のラベル付き初期化に問題はありません。C ++で許可されていないのは、variableの初期化をvariable のスコープに飛び越すことaですa。したがって、Cの観点から見ると、問題はcase VAL:ラベルにあり、あなたはそれを正しく記述しました。しかし、C ++の観点からは、問題はcase ANOTHER_VAL:ラベルにあります。
AnT 2013年

C ++では、Cとは異なり、宣言はステートメントのサブセットです。
キース・トンプソン

20

caseラベルは実際には包含ブロックへのエントリポイントにすぎないため、これを行うことはできません。

これは、Duffのデバイスで最も明確に示されています。ウィキペディアからのコードは次のとおりです。

strcpy(char *to, char *from, size_t count) {
    int n = (count + 7) / 8;
    switch (count % 8) {
    case 0: do { *to = *from++;
    case 7:      *to = *from++;
    case 6:      *to = *from++;
    case 5:      *to = *from++;
    case 4:      *to = *from++;
    case 3:      *to = *from++;
    case 2:      *to = *from++;
    case 1:      *to = *from++;
               } while (--n > 0);
    }
}

caseラベルがブロックの境界を完全に無視していることに注目してください。はい、これは悪です。しかし、これがコード例が機能しない理由です。caseラベルにジャンプすることは、を使用することと同じgotoであるため、コンストラクターを使用してローカル変数をジャンプすることはできません。

他のいくつかのポスターが示しているように、あなたはあなた自身のブロックを置く必要があります:

switch (...) {
    case FOO: {
        MyObject x(...);
        ...
        break; 
    }
    ...
 }

1
このDuffのデバイス実装には、非常に遅くなるバグがあります。カウントはint型であるため、%は実際の除算/剰余演算を実行する必要があります。カウントを署名なしにします(または、カウント/インデックスには常にsize_tを使用します)。問題はなくなります。
R .. GitHub ICEのヘルプ停止

1
@R ..:何ですか?2の補数システムでは、符号化は2の累乗によるモジュロには影響せず(最下位ビットのANDにすぎません)、プロセッサアーキテクチャに算術右シフト演算がある限り、2の累乗による除算には影響しません。 (SARx86では、SHRこれは符号なしシフト用です)。
Chris Jester-Young

@Chris:彼は、「最下位ビットのANDだけ」が成り立たない場合に、コンパイラーが負の値を許可しなければならないときを意味すると私は信じています。たとえば、-1%8は、g ++を使用してこの2の補体系で-1を返します(この場合の記号は、5.6 / 4で定義された実装です)。

3
@Chris:Rが影響を誇張していることに同意します。私はあなたのコメントを見ただけで、簡単なことを知っていて、十分ではありませんでした。

1
また、元のWikipediaのコードは、メモリマップ出力にデータを送信するためのものであることに注意してください。ここでは言及されておらず、すべてのバイトが同じ「宛先」の場所にコピーされるため、ここでは奇妙に見えます。toにpostfix ++を追加するか、メモリマッピングされたIOの使用例に言及することで、これを回避できます。元の質問の完全に周辺:-)。
Peter

16

これまでの返信のほとんどは、1つの点で間違っています。case ステートメントの後に変数宣言できます、変数を初期化することはできません

case 1:
    int x; // Works
    int y = 0; // Error, initialization is skipped by case
    break;
case 2:
    ...

前述のように、これを回避する良い方法は、中括弧を使用してケースのスコープを作成することです。


1
Mr. 32あなたはあなたのエラーが何であるかを誤解しています:はい、コンパイルするつもりはありませんが、スイッチ内で変数を宣言しているからではありません。あなたはC.では違法である文の後に変数を宣言しようとしているため、エラーがある
MrZebra

1
今ではc90およびcの新しいバージョンで合法な日
Jeegar Patel

12

私のお気に入りの邪悪なスイッチトリックは、if(0)を使用して不要なケースラベルをスキップすることです。

switch(val)
{
case 0:
// Do something
if (0) {
case 1:
// Do something else
}
case 2:
// Do something in all cases
}

しかし、非常に悪です。


非常に素晴らしい。理由の例:その後、ケース2で使用され、異なる変数を初期化するインスタンスの場合0とケース1件のかもしれない
hlovdal

1
ケース0とケース1の両方がケース2に該当する場合(ケース0がケース1に該当しない場合)。それが本当に役立つかどうかはわかりませんが、確実に機能します。
ペトルザ

1
gotoコードを難読化せずに、必要なラベルにジャンプできます
SomeWittyUsername


7

新しいブロックを開始する場合は、switchステートメント内で変数を宣言できます。

switch (thing)
{ 
  case A:
  {
    int i = 0;  // Completely legal
  }
  break;
}

その理由は、ローカル変数を格納するためにスタックにスペースを割り当てる(そして再利用する)ためです。


1
変数は宣言できますが、初期化できません。また、問題がスタックとローカル変数に関係しないと確信しています。
Richard Corden、

6

検討してください:

switch(val)
{
case VAL:
   int newVal = 42;
default:
   int newVal = 23;
}

breakステートメントがない場合、newValが2回宣言されることがあり、実行時まで宣言されるかどうかがわかりません。私の推測では、この制限はこの種の混乱のためです。newValのスコープはどのようになりますか?規約により、スイッチブロック全体(中括弧の間)になると規定されています。

私はC ++プログラマではありませんが、Cの場合:

switch(val) {
    int x;
    case VAL:
        x=1;
}

正常に動作します。スイッチブロック内で変数を宣言することは問題ありません。ケースガードの後の宣言はそうではありません。


3
@ Mr.32:実際の例では、printfが実行されないことを示していますが、この場合、int xはステートメントではなく宣言です。xが宣言され、関数環境がスタックされるたびにそのスペースが予約されます。参照:codepad.org/4E9Zuz1e
Petruza

質問は「case:」ラベル内の変数を宣言することではなく、switchステートメント内にあるため、質問のタイトルを読んだときにこれが見つかると予想していました。そして、あなた(そしてあなたの答えを強調したVictorH)だけが実際にswitchステートメントの変数について話しました。
18年

4

スイッチのセクション全体が単一の宣言コンテキストです。そのようなcaseステートメントで変数を宣言することはできません。代わりにこれを試してください:

switch (val)  
{  
case VAL:
{
  // This will work
  int newVal = 42;
  break;
}
case ANOTHER_VAL:  
  ...
  break;
}

変数は宣言できますが、初期化できません。
Richard Corden

@Richard Corden初期化が機能することを確信しています。それでも初期化できないと主張しますか?
chux-モニカを復活させる

3

コードに「int newVal = 42」と表示されている場合は、newValが初期化されていないことが合理的に予想されます。しかし、このステートメント(つまり、あなたがしていること)に進むと、まさにそれが起こります。newValはスコープ内にありますが、割り当てられていません。

それがあなたが本当に起ころうとしていたことなら、言語は「int newVal; newVal = 42;」と言ってそれを明示的にする必要があります。それ以外の場合は、newValのスコープを単一のケースに制限できます。

同じ例ですが、「const int newVal = 42;」を使用すると、説明が明確になる場合があります。


3

私はスリムポイントを強調したかっただけです。スイッチコンストラクトは、完全なファーストクラスのスコープを作成します。したがって、追加のブラケットペアなしで、最初のケースラベルの前にスイッチステートメントで変数を宣言(および初期化)することが可能です。

switch (val) {  
  /* This *will* work, even in C89 */
  int newVal = 42;  
case VAL:
  newVal = 1984; 
  break;
case ANOTHER_VAL:  
  newVal = 2001;
  break;
}

-1 here int newVal = 42; 決して実行されません。このcodepad.org/PA1quYX3を
Jeegar Patel

4
宣言int newVal 実行されますが、= 42割り当ては実行されません。
ペトルザ

3

これまでのところ、答えはC ++に対するものでした。

C ++の場合、初期化を飛び越えることはできません。Cではできますが、Cでは宣言はステートメントではなく、ケースラベルの後にステートメントを続ける必要があります。

したがって、有効な(ただし醜い)C、無効なC ++

switch (something)
{
  case 1:; // Ugly hack empty statement
    int i = 6;
    do_stuff_with_i(i);
    break;
  case 2:
    do_something();
    break;
  default:
    get_a_life();
}

逆に、C ++では、宣言はステートメントなので、以下は有効なC ++、無効なCです。

switch (something)
{
  case 1:
    do_something();
    break;
  case 2:
    int i = 12;
    do_something_else();
}

1
2番目の例は有効なC ++ではありません(vc2010およびgcc 4.6.1を使用したテストC ++では、初期化部分をスキップできません。gccエラーメッセージは次のとおりです: 'int i'の相互初期化
zhaorufei

3

これで問題ないのは興味深いことです。

switch (i)  
{  
case 0:  
    int j;  
    j = 7;  
    break;  

case 1:  
    break;
}

...しかし、これはそうではありません:

switch (i)  
{  
case 0:  
    int j = 7;  
    break;  

case 1:  
    break;
}

修正は非常に簡単であることがわかりますが、なぜ最初の例ではコンパイラーが問題にならないのか、まだわかりません。前に述べたように(2年前のhehe)、宣言は、たとえ論理にもかかわらず、エラーを引き起こすものではありません。初期化が問題です。変数が異なる行で初期化および宣言されている場合は、コンパイルされます。


1
gcc 4.2では最初は問題ありません:「エラー: 'int'の前に式が必要です」。PeterとMr.32が言うように、「case 0:; int j; ...」と「case 0:; int j = 7; ...」はどちらも機能します。Cの問題は、「case <label>:宣言」が有効なC構文ではないということだけです。
dubiousjim

3

私はのためにorginallyこの答えを書いたこの質問。しかし、それを終えたとき、私は答えが閉じられていることに気づきました。だから私はそれをここに投稿しました、おそらく標準への参照を好む人はそれが役に立つと思うでしょう。

問題の元のコード:

int i;
i = 2;
switch(i)
{
    case 1: 
        int k;
        break;
    case 2:
        k = 1;
        cout<<k<<endl;
        break;
}

実際には2つの質問があります。

1.なぜcaseラベルの後に変数を宣言できるのですか?

これは、C ++ではラベルが次の形式でなければならないためです。

N3337 6.1 / 1

ラベル付きステートメント:

...

  • attribute-specifier-seqopt case constant-expressionstatement

...

また、C++ 宣言文は(とは対照的に)と見なされCます。

N3337 6/1:

ステートメント

...

宣言ステートメント

...

2.なぜ変数宣言を飛び越えて使用できるのですか?

理由:N3337 6.7 / 3

ブロックに転送することはできますが、初期化で宣言をバイパスする方法ではできません。ジャンプするプログラム(switchステートメントの条件からcaseラベルへ転送は、この点でジャンプと見なされます。)

自動ストレージ期間を持つ変数がスコープ内にない時点から 、変数がスカラー型、自明なデフォルトコンストラクターおよび自明なデストラクタを持つクラス型(cv修飾バージョン)を持たない限り、その形式が正しくありません。これらのタイプのいずれか、または前述のタイプのいずれかの配列であり、初期化子なしで宣言されている(8.5)。

以来はkであるスカラー型、およびそれの宣言が可能である上、宣言ジャンプの時点で初期化されていません。これは意味的に同等です:

goto label;

int x;

label:
cout << x << endl;

ただしx、宣言時に初期化された場合、それは不可能です。

 goto label;

    int x = 58; //error, jumping over declaration with initialization

    label:
    cout << x << endl;

1

新しい変数は、ブロックスコープでのみデカールできます。次のように書く必要があります:

case VAL:  
  // This will work
  {
  int newVal = 42;  
  }
  break;

もちろん、newValは中括弧内にのみスコープがあります...

乾杯、ラルフ


1

switchブロックは、一連のと同じではありませんif/else ifブロック。他の答えがそれを明確に説明していないことに驚いています。

次のswitchステートメントについて考えてみます。

switch (value) {
    case 1:
        int a = 10;
        break;
    case 2:
        int a = 20;
        break;
}

驚くかもしれませんが、コンパイラーはそれを単純なものとは見なしませんif/else if。次のコードが生成されます。

if (value == 1)
    goto label_1;
else if (value == 2)
    goto label_2;
else
    goto label_end;

{
label_1:
    int a = 10;
    goto label_end;
label_2:
    int a = 20; // Already declared !
    goto label_end;
}

label_end:
    // The code after the switch block

case文はラベルに変換し、その後で呼ばれていますgoto。角括弧は新しいスコープを作成し、switchブロック内で同じ名前の2つの変数を宣言できない理由がすぐにわかります。

奇妙に見えるかもしれませんが、フォールスルーをサポートする必要があります(つまりbreak、次への実行を継続するために使用しないでくださいcase)。


0

当面の問題は、ステートメントがスキップされ、他の場所でvarを使用しようとしたことが宣言されていないことです。


0

newValはスイッチのスコープ全体に存在しますが、VALリムがヒットした場合にのみ初期化されます。VAL内のコードの周囲にブロックを作成する場合は、問題ありません。


0

C ++標準には次のような特徴があります。ブロックに転送することはできますが、初期化で宣言をバイパスする方法ではできません。変数がPODタイプ(3.9)であり、イニシャライザ(8.5)なしで宣言されない限り、自動ストレージ期間を持つローカル変数がスコープ内にないポイントからスコープ内にあるポイントにジャンプするプログラムは、形式が正しくありません。

このルールを説明するコード:

#include <iostream>

using namespace std;

class X {
  public:
    X() 
    {
     cout << "constructor" << endl;
    }
    ~X() 
    {
     cout << "destructor" << endl;
    }
};

template <class type>
void ill_formed()
{
  goto lx;
ly:
  type a;
lx:
  goto ly;
}

template <class type>
void ok()
{
ly:
  type a;
lx:
  goto ly;
}

void test_class()
{
  ok<X>();
  // compile error
  ill_formed<X>();
}

void test_scalar() 
{
  ok<int>();
  ill_formed<int>();
}

int main(int argc, const char *argv[]) 
{
  return 0;
}

イニシャライザ効果を示すコード:

#include <iostream>

using namespace std;

int test1()
{
  int i = 0;
  // There jumps fo "case 1" and "case 2"
  switch(i) {
    case 1:
      // Compile error because of the initializer
      int r = 1; 
      break;
    case 2:
      break;
  };
}

void test2()
{
  int i = 2;
  switch(i) {
    case 1:
      int r;
      r= 1; 
      break;
    case 2:
      cout << "r: " << r << endl;
      break;
  };
}

int main(int argc, const char *argv[]) 
{
  test1();
  test2();
  return 0;
}

0

匿名オブジェクト、参照できないため、次のケースに分類できないという理由で、switch caseステートメントで宣言または作成できるようです。この例がGCC 4.5.3とVisual Studio 2008でコンパイルされることを検討してください(コンプライアンスの問題である可能性があるため、専門家が検討してください)

#include <cstdlib>

struct Foo{};

int main()
{
    int i = 42;

    switch( i )
    {
    case 42:
        Foo();  // Apparently valid
        break;

    default:
        break;
    }
    return EXIT_SUCCESS;
}

反対票を投じる場合は、その理由を説明してください。なぜ匿名オブジェクトの作成が免除のように見えるのか知りたいです。
Olumide

1
DVではありませんが、質問全体は名前付き変数の宣言/スコープに関するものです。一時(「匿名オブジェクト」は用語ではありません)は名前付き変数ではなく、宣言でも、スコープの対象でもありません(const独自のスコープを持つ参照にバインドされている場合を除く)。それは、その声明の中で生きて死ぬ表現です(どこにいても)。したがって、それは完全に無関係です。
underscore_d

Foo();宣言ではありません。問題は宣言についてです。
2017
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.