Namespaces
Variants

switch statement

From cppreference.net
C++ language
General topics
Flow control
Conditional execution statements
switch
Iteration statements (loops)
Jump statements
Functions
Function declaration
Lambda function expression
inline specifier
Dynamic exception specifications ( until C++17* )
noexcept specifier (C++11)
Exceptions
Namespaces
Types
Specifiers
constexpr (C++11)
consteval (C++20)
constinit (C++20)
Storage duration specifiers
Initialization
Expressions
Alternative representations
Literals
Boolean - Integer - Floating-point
Character - String - nullptr (C++11)
User-defined (C++11)
Utilities
Attributes (C++11)
Types
typedef declaration
Type alias declaration (C++11)
Casts
Memory allocation
Classes
Class-specific function properties
Special member functions
Templates
Miscellaneous

条件の値に応じて、複数の文のいずれかに制御を転送します。

目次

構文

attr  (オプション) switch ( init-statement  (オプション) condition ) statement
attr - (since C++11) 任意の数の 属性
init-statement - (since C++17) 以下のいずれか:
(since C++23)

任意の init-statement はセミコロンで終了する必要があることに注意。これが、しばしば非公式に「式または宣言の後にセミコロンが続くもの」と説明される理由である。

condition - 条件
statement - 文(通常は複文)

条件

condition は、 expression または simple declaration のいずれかです。

  • 構文的に structured binding 宣言として解決できる場合、それはstructured binding宣言として解釈されます。
(C++26以降)
  • 構文的に式として解決できる場合は、式として扱われます。それ以外の場合は、構造化束縛宣言ではない宣言として扱われます (since C++26) (C++26以降)
注記: - HTMLタグと属性は翻訳せず、元のフォーマットを保持しました - ` `, `
`, ``タグ内のテキストは翻訳対象外ですが、このテキストには該当しません
- C++専門用語("expression", "declaration", "structured binding declaration")は翻訳せず、技術的な正確性を保ちました
- 重複している"(since C++26)"の部分は、原文の構造を尊重しつつ自然な日本語表現になるよう調整しました

制御が条件に到達すると、条件は値を生成し、その値を使用して制御がどのラベルに進むかを決定します。

condition が式である場合、それが生成する値はその式の値となります。

宣言

condition が単純な宣言である場合、それが生成する値は決定変数の値となります(下記参照)。

非構造化バインディング宣言

この宣言には以下の制限があります:

  • 構文的には以下の形式に従います:
  • type-specifier-seq declarator = assignment-expression
(C++11まで)
  • attribute-specifier-seq (オプション) decl-specifier-seq declarator brace-or-equal-initializer
(C++11以降)

宣言の決定変数は、宣言された変数です。

構造化バインディング宣言

この宣言には以下の制限があります:

この宣言の決定変数は、宣言によって導入される発明された変数 e です

(C++26以降)

condition は以下の型のみを生成できます:

  • 整数型
  • 列挙型
  • クラス型

生成された値がクラス型の場合、文脈的に整数型または列挙型へ暗黙的に変換されます。

もし(変換された可能性のある)型が 整数プロモーション の対象となる場合、生成された値はプロモーション後の型に変換されます。

ラベル

switch 文内の任意のステートメントには、以下のラベルの1つ以上を付けることができます:

attr  (オプション) case constant-expression : (1)
attr  (オプション) default: (2)
attr - (C++11以降) 任意の数の 属性
constant-expression - 変換済み定数式 で、 switch 条件の調整された型のもの


A case または default ラベルは、それを囲む最も内側の switch 文に関連付けられます。

以下のいずれかの条件が満たされる場合、プログラムは不適格となります:

  • switch 文が、変換後の constant-expression の値が同じ複数の case ラベルに関連付けられている。
  • switch 文が複数の default ラベルに関連付けられている。

制御フローの転送

switch 文の条件が(変換された可能性のある)値を返す場合:

  • 関連付けられた case ラベル定数の1つが同じ値を持つ場合、制御は一致した case ラベルで指定された文に移ります。
  • それ以外の場合、関連付けられた default ラベルが存在するならば、制御は default ラベルで指定された文に移ります。
  • それ以外の場合、 switch 文内のどの文も実行されません。

case および default ラベル自体は制御フローを変更しません。 switch 文の途中から抜け出すには、 break を参照してください。

コンパイラはフォールスルー(break文なしで次の case または default ラベルに到達すること)に対して警告を発することがある 。ただし、属性 [[ fallthrough ]] case ラベルの直前に記述されている場合は、そのフォールスルーが意図的であることを示す (C++17以降)

switch (1)
{
    case 1:
        std::cout << '1'; // 「1」を出力し、
    case 2:
        std::cout << '2'; // 続けて「2」を出力
}
switch (1)
{
    case 1:
        std::cout << '1'; // "1"を出力
        break;            // そしてswitch文を終了
    case 2:
        std::cout << '2';
        break;
}

switch 初期化子付きswitch文

init-statement が使用される場合、switch文は以下と等価である:

{
init-statement
switch ( condition ) statement

}

ただし、 init-statement によって宣言された名前( init-statement が宣言である場合)および condition によって宣言された名前( condition が宣言である場合)は同じスコープにあり、これは statement のスコープでもある。

(C++17以降)

注記

制御の転送が変数のスコープに 入ることが許可されていない ため、宣言文が statement 内で見つかった場合、独自の複合文内でスコープされなければなりません:

switch (1)
{
    case 1:
        int x = 0; // 初期化
        std::cout << x << '\n';
        break;
    default:
        // コンパイルエラー: default: へのジャンプ
        // 'x' のスコープに初期化せずに入ることになる
        std::cout << "default\n";
        break;
}
switch (1)
{
    case 1:
        {
            int x = 0;
            std::cout << x << '\n';
            break;
        } // 'x'のスコープはここで終了
    default:
        std::cout << "default\n"; // エラーなし
        break;
}

キーワード

switch case default

以下のコードは switch 文のいくつかの使用例を示しています:

#include <iostream>
int main()
{
    const int i = 2;
    switch (i)
    {
        case 1:
            std::cout << '1';
        case 2:              // 実行はこのcaseラベルから開始
            std::cout << '2';
        case 3:
            std::cout << '3';
            [[fallthrough]]; // C++17のフォールスルー警告を抑制する属性
        case 5:
            std::cout << "45";
            break;           // 以降の文の実行は終了
        case 6:
            std::cout << '6';
    }
    std::cout << '\n';
    switch (i)
    {
        case 4:
            std::cout << 'a';
        default:
            std::cout << 'd'; // 該当する定数式がないため
                              // defaultが実行される
    }
    std::cout << '\n';
    switch (i)
    {
        case 4:
            std::cout << 'a'; // 何も実行されない
    }
    // 列挙型がswitch文で使用される場合、多くのコンパイラは
    // 列挙子の1つが処理されていない場合に警告を発行する
    enum color { RED, GREEN, BLUE };
    switch (RED)
    {
        case RED:
            std::cout << "red\n";
            break;
        case GREEN:
            std::cout << "green\n";
            break;
        case BLUE:
            std::cout << "blue\n";
            break;
    }
    // C++17の初期化文構文は、整数型または列挙型への暗黙的な変換が
    // ない場合に有用である
    struct Device
    {
        enum State { SLEEP, READY, BAD };
        auto state() const { return m_state; }
        /* ... */
    private:
        State m_state{};
    };
    switch (auto dev = Device{}; dev.state())
    {
        case Device::SLEEP:
            /* ... */
            break;
        case Device::READY:
            /* ... */
            break;
        case Device::BAD:
            /* ... */
            break;
    }
    // 病理学的な例
    // 文は複合文である必要はない
    switch (0)
        std::cout << "this does nothing\n";
    // ラベルも複合文を必要としない
    switch (int n = 1)
        case 0:
        case 1:
            std::cout << n << '\n';
}

出力:

2345
d
red
1

不具合報告

以下の動作変更の欠陥報告書は、以前に公開されたC++規格に対して遡及的に適用されました。

DR 適用対象 公開時の動作 正しい動作
CWG 1767 C++98 condition のうち整数昇格の対象とならない型のものは
昇格できなかった
これらの型の condition
昇格しない
CWG 2629 C++98 condition が浮動小数点変数の宣言となりえた 禁止

関連項目

外部リンク

1. ダフのデバイスを使用したループ展開
2. ダフのデバイスはC/C++でコルーチンを実装するために使用できる