整数式の値に応じてコードの複数のセクション間を切り替えます。
構文
selection-statement=
switch(init-statementopt C++17condition)statement
init-statement=
expression-statement
simple-declaration
condition=
expression
attribute-specifier-seqoptdecl-specifier-seqdeclaratorbrace-or-equal-initializer
labeled-statement=
caseconstant-expression:statement
default:statement
注釈
switch ステートメントを指定すると、 の値に応じて、ステートメント本体の 1 つの labeled-statementcondition にコントロールが転送されます。
condition は整数型を持つか、整数型への明確な変換を持つクラス型である必要があります。 「標準変換」で説明されているように整数の上位変換が実行されます。
switch ステートメントの本体は、一連の case ラベルとオプションの default ラベルで構成されます。
labeled-statement は、これらのラベルのいずれかと、それに続くステートメントです。 ラベル付きステートメントは構文上の要件ではありませんが、それらがないと switch ステートメントを使用する意味がありません。
constant-expression ステートメント内の 2 つの case 値が同じ値に評価されてはなりません。
default ラベルは 1 回だけ指定できます。
default ステートメントは、多くの場合末尾に置かれますが、switch ステートメント本体内の任意の場所に置くことができます。
case または default ラベルは、 switch ステートメント内でのみ使用できます。
各 constant-expression ラベルの case は、condition と同じ型の定数値に変換されます。 その後、condition と等しいかどうか比較されます。 制御は case という値に一致する constant-expressioncondition 値の後の最初のステートメントに移動します。 結果の動作を次の表に示します。
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) );
}
上の例では、uppercase_A は c が大文字 'A' の場合、インクリメントします。
break の後の uppercase_A++ ステートメントによって switch ステートメント本体の実行が終了し、制御が while ループに移ります。
break ステートメントを使用しない場合、実行は次のラベル付きステートメントに "フォール スルー" され、lowercase_a と other もインクリメントされます。
break の case 'a' ステートメントも、同様の目的で使用しています。
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++ では、case ステートメント内の switch 値の数が制限されません。 この数は、使用できるメモリによってのみ制限されます。