switch ステートメント (C++)

整数式の値に応じてコードの複数のセクション間を切り替えます。

構文

selection-statement=
switch(init-statementoptC++17condition)statement

init-statement=
expression-statement
simple-declaration

condition=
expression
attribute-specifier-seqopt decl-specifier-seq declarator brace-or-equal-initializer

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

注釈

switch ステートメントを指定すると、 の値に応じて、ステートメント本体の 1 つの conditionlabeled-statement にコントロールが転送されます。

condition は整数型を持つか、整数型への明確な変換を持つクラス型である必要があります。 「標準変換」で説明されているように整数の上位変換が実行されます。

switch ステートメントの本体は、一連の case ラベルと省略可能な default ラベルで構成されます。 labeled-statement は、これらのラベルのいずれかと、それに続くステートメントです。 ラベル付きステートメントは構文上の要件ではありませんが、それらがないと switch ステートメントを使用する意味がありません。 case ステートメント内の 2 つの constant-expression 値が同じ値に評価されてはなりません。 default ラベルは 1 回だけ指定できます。 default ステートメントは、多くの場合末尾に置かれますが、switch ステートメント本体内の任意の場所に置くことができます。 case または default ラベルは、 switch ステートメント内でのみ使用できます。

case ラベルの constant-expression は、condition と同じ型の定数値に変換されます。 その後、condition と等しいかどうか比較されます。 condition の値に一致する caseconstant-expression 値の後、制御は最初のステートメントに渡されます。 結果の動作を次の表に示します。

switch ステートメントの動作

状態 アクション
変換後の値は、上位変換された制御式の値と一致します。 制御は、そのラベルの次のステートメントに移ります。
定数のいずれも case ラベル内の定数と一致しない。default ラベルが存在する。 制御は default ラベルに移動します。
定数のいずれも case ラベル内の定数と一致しない。default ラベルが存在しない。 制御は switch ステートメントの後のステートメントに移動します。

一致する式が見つかった場合、実行は後の case ラベルや default ラベルを通して続行できます。 break ステートメントは、実行を停止し、switch ステートメントの後のステートメントに制御を移すために使用されます。 break ステートメントがない場合は、一致する case ラベルから switch ステートメントの最後までのすべてのステートメントが、default 句も含めて実行されます。 次に例を示します。

// switch_statement1.cpp
#include <stdio.h>

int main() {
   const char *buffer = "Any character stream";
   int uppercase_A, lowercase_a, other;
   char c;
   uppercase_A = lowercase_a = other = 0;

   while ( c = *buffer++ )   // Walks buffer until NULL
   {
      switch ( c )
      {
         case 'A':
            uppercase_A++;
            break;
         case 'a':
            lowercase_a++;
            break;
         default:
            other++;
      }
   }
   printf_s( "\nUppercase A: %d\nLowercase a: %d\nTotal: %d\n",
      uppercase_A, lowercase_a, (uppercase_A + lowercase_a + other) );
}

上の例では、c が大文字の 'A' である場合、uppercase_A をインクリメントします。 uppercase_A++ の後の break ステートメントによって switch ステートメント本体の実行が終了し、制御が while ループに移ります。 break ステートメントを使用しない場合、実行は次のラベル付きステートメントに "フォール スルー" され、lowercase_aother もインクリメントされます。 case 'a'break ステートメントも、同様の目的で使用しています。 c が小文字の 'a' である場合、lowercase_a がインクリメントされ、break ステートメントによって switch ステートメントの本体が終了します。 c'a' でも 'A' でもない場合は、default ステートメントが実行されます。

Visual Studio 2017 以降 (/std:c++17 モード以降で使用可能): [[fallthrough]] 属性は C++17 標準で指定されます。 これを switch ステートメント内で使用できます。 これは、コンパイラ、またはコードを読む人に対して、フォールスルー動作が意図的であることを示すヒントです。 現在、Microsoft C++ コンパイラでは、フォールスルー動作に関する警告は行わないので、この属性はコンパイラの動作に影響しません。 次の例では、終了されないラベル付きステートメント内の空のステートメントに、この属性が適用されます。 つまり、セミコロンは必要です。

int main()
{
    int n = 5;
    switch (n)
    {

    case 1:
        a();
        break;
    case 2:
        b();
        d();
        [[fallthrough]]; // I meant to do this!
    case 3:
        c();
        break;
    default:
        d();
        break;
    }

    return 0;
}

Visual Studio 2017 バージョン 15.3 以降 (/std:c++17 モード以降で使用可能): switch ステートメントに、セミコロンで終わる init-statement 句を含めることができます。 これにより変数が導入されて初期化されます。そのスコープは switch ステートメントのブロックに制限されます。

    switch (Gadget gadget(args); auto s = gadget.get_status())
    {
    case status::good:
        gadget.zip();
        break;
    case status::bad:
        throw BadGadget();
    };

switch ステートメントの内部ブロックには、定義と初期化子を含めることができます ("到達可能" である (すべての可能な実行パスで回避されない) 限り)。 これらの宣言を使用して導入された名前にはローカル スコープがあります。 次に例を示します。

// switch_statement2.cpp
// C2360 expected
#include <iostream>
using namespace std;
int main(int argc, char *argv[])
{
    switch( tolower( *argv[1] ) )
    {
        // Error. Unreachable declaration.
        char szChEntered[] = "Character entered was: ";

    case 'a' :
        {
        // Declaration of szChEntered OK. Local scope.
        char szChEntered[] = "Character entered was: ";
        cout << szChEntered << "a\n";
        }
        break;

    case 'b' :
        // Value of szChEntered undefined.
        cout << szChEntered << "b\n";
        break;

    default:
        // Value of szChEntered undefined.
        cout << szChEntered << "neither a nor b\n";
        break;
    }
}

switch ステートメントは入れ子にすることもできます。 入れ子にすると、case ラベルや default ラベルは、そのすぐ外側の switch ステートメントと関連付けられます。

Microsoft 固有の動作

Microsoft C++ では、switch ステートメント内の case 値の数が制限されません。 この数は、使用できるメモリによってのみ制限されます。

関連項目

選択ステートメント
キーワード