【C++】enum class – スコープを持つ列挙型

C++

はじめに

C++11より、従来の列挙型を拡張したenum classが追加されました。これにより、より安全に列挙型を使うことができるようになります。このエントリでは、enum classについてまとめてみました。

特徴

  1. スコープを持つため、名前の衝突を避けることができる
  2. 整数型への暗黙の型変換を行わない
  3. 整数型の基底型(char, unsigned intなど)を指定することができる
  4. enum classで定義された値以外は使用できない

使い方

定義方法

enum class 型名 : 基底型 {
    列挙子1 = 整数値, 列挙子2, ...
};

従来の列挙型と同じような方法で定義可能です。enum classenum structでも構いません。どちらの方法でも機能的な違いはありません。

基底型を指定しなかった場合はint型となります。また、整数値を指定しなかった場合は、前の値に+1した値が割り当てられる点は、従来の列挙型と同じです。基底型を指定した場合、その基底型の範囲を超えるような値を使うことはできません。

使用例

// 定義
enum class Number : unsigned int {
    Zero = 0, One, Two, Three
};

// 変数の宣言
Number v;

// 変数への代入
v = Number::One;
// v = 4 // <- 定義した値以外は代入できない

// 整数型変数への代入
unsigned int int_v = static_cast<unsigned int>(v);
// unsigned int int_v = v // <- 基底型が同じでも直接代入はできない

従来のenumと違い、定義した値はスコープを持つため、アクセスするには必ず型名::列挙子の形にしなければなりません。ちょっと面倒ですが、これにより名前の衝突を避けることができます。名前空間ではないので、usingを使って省略することはできません。

また、定義した値以外は使うことができません。宣言した変数にただの整数値を代入することはできません。

注意が必要なのは、整数型変数への代入や、整数値として扱いたい場合です。この場合は、型をstatic_cast<>()を使ってキャストする必要があります。基底型が同じであってもキャストが必要です。

// 変数の比較
if(v == Number::Zero){
    ...
}
else if(v >= Number::One){
    ...
}

switch(v){
case Number::Zero:
    ...
default:
    ...
}

比較は、従来と同じように行うことができます。等号だけでなく、不等号も使えます。定義値以外の整数値と比較する場合は、キャストが必要です。

まとめ

スコープを持つ列挙型enum classについてまとめてみました。

  1. スコープを持つため、名前の衝突を避けることができる
  2. 整数型への暗黙の型変換を行わない。整数型として扱う場合は、static_cast<>()による型変換が必要
  3. 整数型の基底型を指定することができる。このとき、基底型を超える範囲の値は定義できない
  4. enum classで定義された値以外は使用できない
  5. 定義された値との比較は、従来と同様に書くことができる

C++

Posted by izadori