- cpp11[meta cpp]
このページはC++11に採用された言語機能の変更を解説しています。
のちのC++規格でさらに変更される場合があるため関連項目を参照してください。
enum class
で定義した列挙型は、従来のenum
に加えて、「整数型への暗黙の型変換を行わない」「列挙型のスコープを持つ」という機能を持つ。
enum class Color { Red, Green, Blue };
// 単にRedと指定するのではなく、どの列挙型に属するのかを指定する
Color c = Color::Red;
// 明示的な型変換は許可する
int color = static_cast<int>(Color::Red);
//int color = Color::Red; // コンパイルエラー : 暗黙の型変換はできない
-
enum class
もしくはenum struct
で定義した列挙型は、「スコープを持つ列挙型 (scoped enumeration type)」という。enum class
とenum struct
に、機能の違いはない -
enum
で定義した列挙型は、「スコープを持たない列挙型 (unscoped enumeration type)」という -
列挙型には、型名の後ろにコロン
:
区切りで、基底の整数型を指定できる。基底型として指定した整数型のCV修飾は無視される// 基底型をintとする enum class Color : int { Red, Green, Blue };
- 列挙子の値が基底型の範囲に収まらない場合、プログラムは不適格となる
- 列挙型の基底型を取得するには、
<type_traits>
ヘッダで定義されるstd::underlying_type
を使用する
-
列挙型は、先行宣言でも基底型を指定できる。その場合、再宣言および定義でも、同じ基底型を明示的に指定する必要がある
-
スコープを持つ列挙型に基底型を指定しない場合、基底型は
int
となる -
スコープを持たない列挙型に基底型を指定しない場合、その列挙型の全ての列挙子の値を表現できる整数型のいずれかが基底型となる(どの整数型となるかは実装定義だが、すべての列挙子の値が
int
もしくはunsigned int
に収まる限りint
より大きな型にはならない) -
スコープを持たない列挙型の列挙子が空である場合、値
0
ひとつを列挙子として持つ -
2つの列挙型の基底型が同じである場合、それらの列挙型は互換性のあるメモリレイアウトを持つ
-
列挙子に値を指定しない場合、最初の列挙子には定数値
0
が設定される。2つ目以降の列挙子は、ひとつ前の値を1
進めた値を持つ
スコープを持つ列挙型の導入に合わせて、スコープを持たない列挙型もC++11で以下の機能拡張が行われた
- 基底型を指定できるようになった
- 基底型が指定されている場合は、先行宣言ができるようになった
- 列挙型名をスコープとして書けるようになった (
列挙型名::列挙子
が許可された)
詳細は、上述した仕様を参照。
#include <cassert>
#include <type_traits>
enum class Color { Red, Green, Blue };
enum class CharColor : char { Red, Green, Blue }; // 基底型をcharにする
int main()
{
// 単にRedと指定するのではなく、どの列挙型に属するのかを指定する
Color c = Color::Red;
// 明示的な型変換は許可する
int colorValue = static_cast<int>(Color::Red);
//int colorValue = Color::Red; // コンパイルエラー : 暗黙の型変換はできない
assert(colorValue == 0);
// 列挙型の基底型を取得して、その型にキャスト
auto colorValue2 = static_cast<std::underlying_type<Color>::type>(Color::Red);
assert(colorValue2 == 0);
}
- std::underlying_type[link /reference/type_traits/underlying_type.md]
C++03は、C99の列挙型に対する改善は提供していたが、依然として以下のような問題が残っていた:
- 型の安全性
- 予期しないエラー(スコープがないことによる名前衝突、上記の型安全性の問題による予期しない型変換)
- コードのわかりやすさ(明確さ)
- コードの移植性
ECMA規格になっているC++/CLIが、現在のスコープを持つ列挙型と等価の機能を持っていたために、その経験を標準C++に取り入れることとなった。