【C++】switch文が使えないケースとは?|文字列・小数・範囲指定を完全解説

サムネイル画像 C++

C++のswitch文を書いていて、「文字列や小数で分岐できないの?」「なぜコンパイルエラーになるの?」と困ったことはありませんか?

実は、switch文は「何でも条件に使える」わけではなく、整数型として扱える値だけという厳しい制限があります。

この記事を読み終えると、あなたはswitch文の制限と、それぞれのケースでの対処法を完全に理解できると思いますので、ぜひ最後まで読んでいただけると嬉しいです。

switch文に使える値のルール

switch文の条件式に使えるのは、基本的に以下の3つだけです。

  • 整数型(int / char / short / long など)
  • enum(列挙型)
  • constexpr な値(コンパイル時定数)

逆に言うと、これ以外はすべて使えません。

それでは、具体的に「使えないケース」を見ていきましょう。

使えないケース① double / float は使えない

小数型(浮動小数点数)はswitch文で使えません。

▼main.cpp

#include <iostream>

int main() {
    double x = 1.5;
    
    // ❌ コンパイルエラー
    // switch (x) {
    //     case 1.5:
    //         std::cout << "1.5です\n";
    //         break;
    // }
    
    return 0;
}

エラーメッセージ(例)

error: switch quantity not an integer

なぜ使えないのか?

switch文は内部的にジャンプテーブルという高速分岐を使うため、値が離散的(飛び飛び)である必要があります。

浮動小数点数は連続的で、誤差もあるため、switch文の仕組みでは扱えません。

対処法:if文を使う

▼main.cpp

#include <iostream>

int main() {
    double x = 1.5;
    
    // ✅ if文を使う
    if (x == 1.5) {
        std::cout << "1.5です\n";
    } else if (x == 2.5) {
        std::cout << "2.5です\n";
    } else {
        std::cout << "その他\n";
    }
    
    return 0;
}

実行結果

1.5です

使えないケース② std::string は使えない

文字列(std::string)もswitch文で使えません。

▼main.cpp

#include <iostream>
#include <string>

int main() {
    std::string cmd = "start";
    
    // ❌ コンパイルエラー
    // switch (cmd) {
    //     case "start":
    //         std::cout << "ゲーム開始\n";
    //         break;
    // }
    
    return 0;
}

エラーメッセージ(例)

error: switch quantity not an integer

なぜ使えないのか?

switch文は文字列比較の仕組みを持たないため、std::stringは扱えません。

対処法:if-else や map を使う

▼main.cpp(if-else版)

#include <iostream>
#include <string>

int main() {
    std::string cmd = "start";
    
    // ✅ if-else を使う
    if (cmd == "start") {
        std::cout << "ゲーム開始\n";
    } else if (cmd == "load") {
        std::cout << "ロード\n";
    } else if (cmd == "exit") {
        std::cout << "終了\n";
    } else {
        std::cout << "無効なコマンド\n";
    }
    
    return 0;
}

実行結果

ゲーム開始

▼main.cpp(map版 – より高速)

#include <iostream>
#include <string>
#include <unordered_map>

int main() {
    std::string cmd = "start";
    
    // ✅ mapで疑似switch
    std::unordered_map<std::string, int> cmdMap = {
        {"start", 1},
        {"load", 2},
        {"exit", 3}
    };
    
    switch (cmdMap[cmd]) {
        case 1:
            std::cout << "ゲーム開始\n";
            break;
        case 2:
            std::cout << "ロード\n";
            break;
        case 3:
            std::cout << "終了\n";
            break;
        default:
            std::cout << "無効なコマンド\n";
    }
    
    return 0;
}

実行結果

ゲーム開始

使えないケース③ 実行時に決まる値は case に書けない

これも初心者が超混乱するポイントです。

▼main.cpp

#include <iostream>

int main() {
    int a = 10;
    int b = 20;
    
    // ❌ コンパイルエラー
    // switch (a) {
    //     case b:  // 変数bは使えない
    //         std::cout << "bと一致\n";
    //         break;
    // }
    
    return 0;
}

エラーメッセージ(例)

error: case label does not reduce to an integer constant

なぜ使えないのか?

caseに書ける値はコンパイル時定数のみです。実行時に決まる変数は使えません。

対処法:定数や enum を使う

▼main.cpp

#include <iostream>

int main() {
    int a = 10;
    const int b = 10; // ✅ constなら使える
    
    switch (a) {
        case b:
            std::cout << "bと一致\n";
            break;
        case 20:
            std::cout << "20\n";
            break;
    }
    
    return 0;
}

実行結果

bと一致

使えないケース④ 範囲指定はできない

「スコアが80~100点なら優」のような範囲指定はswitch文でできません。

▼main.cpp

#include <iostream>

int main() {
    int score = 85;
    
    // ❌ C++標準では不可(GCC拡張では可能だが非推奨)
    // switch (score) {
    //     case 80 ... 100:
    //         std::cout << "優\n";
    //         break;
    // }
    
    return 0;
}

なぜ使えないのか?

C++標準では範囲指定の構文が未対応です。(GCCコンパイラの拡張機能としては存在しますが、移植性がありません)

対処法:if文を使う

▼main.cpp

#include <iostream>

int main() {
    int score = 85;
    
    // ✅ if文で範囲指定
    if (score >= 80 && score <= 100) {
        std::cout << "優\n";
    } else if (score >= 60) {
        std::cout << "良\n";
    } else {
        std::cout << "不可\n";
    }
    
    return 0;
}

実行結果

使えないケース⑤ bool は実質使えない

bool型はswitch文で書けなくはないですが、意味が薄いです。

▼main.cpp

#include <iostream>

int main() {
    bool flag = true;
    
    // 書けるけど...
    switch (flag) {
        case true:
            std::cout << "真\n";
            break;
        case false:
            std::cout << "偽\n";
            break;
    }
    
    return 0;
}

実行結果

対処法:普通に if で良い

▼main.cpp

#include <iostream>

int main() {
    bool flag = true;
    
    // ✅ if の方が自然
    if (flag) {
        std::cout << "真\n";
    } else {
        std::cout << "偽\n";
    }
    
    return 0;
}

実行結果

boolはtrue/falseの2値しかないため、switchを使う意味がありません。

【重要】私が実際にswitch文で困った体験談

体験談1: コマンドを文字列で分岐しようとしてエラー

自主制作で「テキストベースのRPG」を作っていた時のことです。プレイヤーの入力コマンドで分岐する処理を以下のように書きました。

std::string command;
std::cin >> command;

switch (command) {  // ❌ エラー!
    case "attack":
        std::cout << "攻撃!\n";
        break;
    case "defend":
        std::cout << "防御!\n";
        break;
}

コンパイルすると、「switch quantity not an integer」というエラーが出ました。

原因を調べたところ、switch文は文字列が使えないことを初めて知りました。結局、if-elseで書き直しました。

// ✅ if-else で解決
if (command == "attack") {
    std::cout << "攻撃!\n";
} else if (command == "defend") {
    std::cout << "防御!\n";
}

体験談2: スコア判定で範囲指定しようとしてエラー

自主制作でクイズゲームを作っていた時、スコアの範囲で成績を判定する処理を以下のように書きました。

int score = 85;

switch (score) {
    case 80 ... 100:  // ❌ エラー!
        std::cout << "優\n";
        break;
    case 60 ... 79:
        std::cout << "良\n";
        break;
}

GCCでは動いたのですが、Visual Studioでビルドするとエラーになりました。

原因は、範囲指定がC++標準ではなく、GCC拡張機能だったこと。if文に書き直したら、どの環境でも動くようになりました。

// ✅ if文で解決
if (score >= 80) {
    std::cout << "優\n";
} else if (score >= 60) {
    std::cout << "良\n";
}

よくある失敗例と対処法

失敗例1: 変数をcaseに書いてエラー

症状: case label does not reduce to an integer constant
原因: caseには定数しか書けない
対処法: constenum、リテラル値を使う

// NG
int max = 100;
switch (score) {
    case max:  // 変数は使えない
        break;
}

// OK
const int MAX = 100;
switch (score) {
    case MAX:  // 定数なら使える
        break;
}

失敗例2: charポインタ(C文字列)で分岐しようとした

症状: switch quantity not an integer
原因: C文字列(char*)は文字列ではなくポインタ
対処法: if文でstrcmpを使うか、std::stringでif-else

// NG
const char* cmd = "start";
switch (cmd) {  // ポインタは使えない
    case "start":
        break;
}

// OK(strcmp使用)
#include <cstring>
if (strcmp(cmd, "start") == 0) {
    // ...
}

失敗例3: 小数を整数に丸めて使おうとした

症状: 思った通りに分岐しない
原因: 丸め誤差や変換ミス
対処法: 最初からif文で小数比較する

// NG(誤差が出る可能性)
double x = 1.5;
switch ((int)x) {  // 1になる
    case 1:
        break;
}

// OK
if (x == 1.5) {
    // ...
}

switch文を使うべき場面

switch文が向いているのは以下のような場面です。

  • 状態管理(ゲームのシーン遷移など)
  • メニュー処理(1=新規、2=ロード、3=終了)
  • enum 分岐(列挙型による分岐)
  • 固定値分岐(整数の一致判定)

▼良い例(enum使用)

#include <iostream>

enum State { TITLE, PLAY, RESULT };

int main() {
    State state = PLAY;
    
    switch (state) {
        case TITLE:
            std::cout << "タイトル画面\n";
            break;
        case PLAY:
            std::cout << "ゲーム中\n";
            break;
        case RESULT:
            std::cout << "リザルト\n";
            break;
    }
    
    return 0;
}

実行結果

ゲーム中

switch vs if 比較表

比較項目switchif
整数型
小数型×
文字列×
範囲指定×
複雑な条件×
見やすさ(分岐多)
速度(分岐多)

まとめ

switch文の制限をまとめます。

  • 使えるのは整数型・enum・定数のみ
  • double/floatは使えない → if文を使う
  • std::stringは使えない → if-else か map+switch
  • 変数はcaseに書けない → 定数のみ
  • 範囲指定は不可 → if文を使う
  • boolは実質不要 → 普通にifでOK
  • 向いているのは状態管理・enum・固定値分岐

これでswitch文の制限と対処法はバッチリですね!

使えない場面では無理せずif文を使うのが正解です。

ここまで読んでくださり、ありがとうございました。

この記事が皆様の学習に役立てば幸いです。

関連記事