読者です 読者をやめる 読者になる 読者になる

C++11:スコープ付きの強く型付けされた列挙体:enum class

C++ C++11

C++11では、enum(従来の列挙体)の3つの問題を解決したenum classが導入された。

  • 暗黙的にint型へ変換できるため、整数として振舞わせたくない場合にエラーの原因となる。
  • 列挙子がスコープの外から見えるため、名前の衝突を引き起こす。
  • 根底型(内部表現として利用される型)を指定できないため、混乱や互換性の問題の元となる。また、前方宣言できない。

enum classは、強く型付けされる。

enum Alert { red, blue };       // 従来の列挙体
enum class Color { red, blue }; // スコープ付きの強く型付けされた列挙体

Alert a1 = 7;           // エラー:int型からの変換不可
Color c1 = 7;           // エラー:int型からの変換不可

int a2 = red;           // OK
int c2 = Color::red;    // エラー:int型への変換不可

Alert a3 = blue;        // OK
Color c3 = Color::blue; // OK

enum classの列挙子は、列挙体のスコープに入る。

enum Alert { red, blue };
enum class Color { red, blue };

enum Foo { red, blue };         // エラー:名前の衝突
enum class Bar { red, blue };   // OK

Alert a1 = blue;        // OK
Color c1 = blue;        // エラー

Alert a2 = Alert::blue; // OK(C++98では不可)
Color c2 = Color::blue; // OK

根底型を指定できるようになったことで、列挙体の相互運用性と大きさの保障が単純になった。

enum Alert { red, blue };             // 実装定義(C言語ではint)
enum class Color: char { red, blue }; // 1バイト

根底型には汎整数型(論理型、文字型、整数型)を指定でき、デフォルトではint型となる。
前方宣言も可能になった。

// 前方宣言
enum Alert;             // エラー
enum class Color: char; // OK

// 前方宣言の利用
void foo(Alert a); // エラー
void bar(Color c); // OK

// 定義
enum Alert { red, blue };
enum class Color: char { red, blue };

なお、C++11では、単なるenumでも根底型を指定でき、その場合は前方宣言もできる。

// 前方宣言
enum Alert: char; // OK

// 前方宣言の利用
void foo(Alert a);

// 定義
enum Alert: char { red, blue };

マイコーディングルール

  • 単なるenumではなく、enum classを使う。

参考