C++/列挙型と列挙クラス

出典: フリー教科書『ウィキブックス(Wikibooks)』
< C++

列挙型の基本[編集]

列挙型(enum: enumeration)は、関連する値の集合を表現するための型です。プログラムのコードの可読性を高め、型安全性を確保するために使用されます。

列挙型の定義は次のように行います。

enum 列挙型名 { 列挙子1, 列挙子2, ... };

たとえば、曜日を表す列挙型は次のように定義できます。

enum DayOfWeek { Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday };

列挙型の変数を宣言し、特定の値を代入することができます。

DayOfWeek today = Monday;

デフォルトでは、列挙子には0から始まる連続した値が自動的に割り当てられます。しかし、明示的に値を指定することもできます。

enum Color { Red = 1, Green = 5, Blue = 10 };


列挙型の利点[編集]

列挙型を使用することで、次のような利点があります。

型安全性の確保
列挙型は特定の値の集合に制限されるため、不適切な値の代入を防ぐことができます。
コードの可読性向上
列挙子の名前を使用することで、コードの意図がわかりやすくなります。
デバッグ性の向上
コードのエラーを見つけやすくなります。

従来の列挙型の制限[編集]

従来の列挙型には次のような制限があります。

型の変換
列挙型は暗黙的に整数型に変換されてしまうため、型安全性が損なわれる可能性があります。
名前の衝突
同じスコープ内で同じ列挙子名を使用することはできません。
機能の限界
列挙型には演算子のオーバーロードやメンバ関数の定義ができません。

列挙クラス(C++11)[編集]

C++11で導入された列挙クラスは、従来の列挙型の制限を解決しています。

列挙クラスの定義は次のようになります。

enum class 列挙クラス名 { 列挙子1, 列挙子2, ... };

列挙クラスはスコープ列挙型であり、クラスとして扱われます。列挙クラスのインスタンスを作成して使用します。

enum class Color { Red, Green, Blue };
Color c = Color::Red;

列挙クラスには、メンバ関数を定義することができます。

enum class Color { Red, Green, Blue, 
    Color_Count // 列挙子の数を表す
};

int getColorCount() {
    return static_cast<int>(Color::Color_Count);
}

前方宣言も可能で、名前空間に列挙クラスを配置することもできます。

namespace Colors {
enum class Color; // 前方宣言
}

namespace Shapes {
enum class Color; // 別の名前空間での宣言
}

列挙クラスの拡張機能(C++20)[編集]

C++20では、列挙クラスにいくつかの拡張機能が追加されました。

値の初期化[編集]

列挙子に値を初期化することができます。

enum class Tile {
    Grass = 0,
    Water = 10,
    Stone = 25
};

列挙クラスのフレンド関数[編集]

非メンバ関数を列挙クラスのフレンド関数として宣言できます。

enum class Fruit { Apple, Banana, Orange };

Fruit operator+(Fruit f1, Fruit f2) {
    // 演算の実装
}

カスタム演算子のオーバーロード[編集]

列挙クラス内で演算子をオーバーロードすることができます。

enum class Bits : unsigned char {
    No_Bit   = 0,
    Bit_1    = 1 << 0,
    Bit_2    = 1 << 1,
    Bit_3    = 1 << 2,
    
    Bits operator~() const {
        return static_cast<Bits>(~static_cast<unsigned char>(*this));
    }
};

列挙クラスのカスタムリテラル[編集]

列挙クラスに対してカスタムリテラルを定義できます。

enum class Byte : unsigned char {};

Byte operator""_Byte(unsigned long long arg) {
    return static_cast<Byte>(arg);
}

int main() {
    Byte b = 255_Byte; // OK
    return 0;
}

ベストプラクティス[編集]

列挙型や列挙クラスを使用する際には、次のようなベストプラクティスに従うことが推奨されます。

命名規則
列挙型や列挙クラスの名前は大文字から始める(UpperCamelCase)。列挙子の名前はすべて大文字で定義する(UPPER_CASE)。
使用例
状態、オプション、フラグなどの値の集合を表現する際に使用する。
組み合わせ
他の型と組み合わせて使用することで、さらに柔軟性が高まる。

まとめ[編集]

列挙型と列挙クラスは、関連する値の集合を安全に表現するための機能です。列挙クラスはC++11で導入され、従来の列挙型の制限を解決しています。C++20ではさらに機能が拡張され、より柔軟な利用が可能になっています。型安全性の確保と、コードの可読性、デバッグ性の向上のために、積極的に列挙型と列挙クラスを活用することをお勧めします。