名前空間
変種
操作

列挙宣言

提供: cppreference.com
< cpp‎ | language
 
 
 
 

列挙は、いくつかの明示的に名前を付けられた定数 (「列挙子」) を含む特定の範囲に値が制限される (詳細は後述)、独立した型です。 定数の値は列挙のベースとなる型と呼ばれる整数型の値です。

列挙は以下の構文を用いて定義されます。

enum-key attr(オプション) enum-name(オプション) enum-base(オプション)(C++11) { enumerator-list(オプション) } (1)
enum-key attr(オプション) enum-name enum-base(オプション) ; (2) (C++11以上)
1) enum 指定子 (宣言の構文の decl-specifier-seq に現れます) は列挙型およびその列挙子を定義します。
2) 不透明な列挙の宣言。 列挙型を定義しますが、その列挙子は定義しません。 この宣言の後、その型は完全型であり、そのサイズは既知です。 ノート: クラステンプレートのスコープ付き列挙メンバの明示的特殊化の宣言enum-name の前に nested-name-specifier が現れる唯一のケースです。 (C++14以上)
enum-key - enumenum class(C++11以上) または enum struct(C++11以上) のいずれか。
attr(C++11) - オプショナルな任意個の属性の並び。
enum-name - 宣言されている列挙の名前。 存在する場合、およびこの宣言が再宣言の場合は、 nested-name-specifier(C++11以上) (スコープ解決演算子で終わる名前とスコープ解決演算子 :: の並び) を前に置いても構いません。 名前はスコープなし列挙の宣言においてのみ省略できます。
enum-base(C++11) - コロン (:) の後に、この列挙型に対する固定のベースとなる型として用いられる、整数型を表す type-specifier-seq が続いたもの (cv 修飾されている場合、修飾は無視されます)。
enumerator-list - 列挙子の定義のコンマ区切りのリスト。 各々は単に identifier (列挙の名前になります) であるか、または初期化子付きの識別子 identifier = constexpr であるかのいずれかです。 いずれの場合でも、 identifier はオプショナルな属性指定子の並びを直後に付けることができます。 (C++17以上)

2種類の異なる列挙があります。 スコープなし列挙 (enum-key enum を用いて宣言されたもの) とスコープ付き列挙 (enum-key enum class または enum struct を用いて宣言されたもの) です。

目次

[編集] スコープなし列挙

enum name { enumerator = constexpr , enumerator = constexpr , ... } (1)
enum name : type { enumerator = constexpr , enumerator = constexpr , ... } (2) (C++11以上)
enum name : type ; (3) (C++11以上)
1) ベースとなる型が固定されていないスコープなし列挙型を宣言します (この場合、ベースとなる型はすべての列挙子の値を表現できる処理系定義の整数型です。 この型は、列挙の値を int または unsigned int に収めることができないのでない限り、 int より大きくありません。 enumerator-list が空の場合、ベースとなる型は列挙が値 0 の単一の列挙子を持っているかのように決定されます)。
2) ベースとなる型が固定されているスコープなし列挙型を宣言します。
3) スコープなし列挙に対する不透明な列挙の宣言はベースとなる型を指定しなければなりません。

それぞれの enumerator は、囲っているスコープで可視な、その列挙の型 (つまり name) の名前付き定数になり、定数が要求されるときにいつでも使用することができます。

enum Color { red, green, blue };
Color r = red;
switch(r)
{
    case red  : std::cout << "red\n";   break;
    case green: std::cout << "green\n"; break;
    case blue : std::cout << "blue\n";  break;
}

それぞれの列挙子はベースとなる型の値が紐付けられます。 enumerator-list 内で初期化子が提供されているときは、列挙子の値はそれらの初期化子によって定義されます。 最初の列挙子が初期化子を持たない場合、紐付けられる値はゼロです。 定義に初期化子を持たないそれ以外のあらゆる列挙子の場合、紐付けられる値は前の列挙子の値プラス1です。

enum Foo { a, b, c = 10, d, e = 1, f, g = f + c };
//a = 0, b = 1, c = 10, d = 11, e = 1, f = 2, g = 12

スコープなし列挙型の値は整数型に暗黙に変換されます。 ベースとなる型が固定されていない場合、値は intunsigned intlongunsigned longlong longunsigned long long のうちその値の範囲全体を保持できる最初の型に変換可能です。

enum color { red, yellow, green = 20, blue };
color col = red;
int n = blue; // n == 21

整数型、浮動小数点型、および列挙型の値は、 static_cast または明示的なキャストによって、任意の列挙型に変換できます。 ベースとなる型が固定されておらず、元の値が範囲外の場合、結果は未規定 (C++17未満)未定義 (C++17以上)です (元の値 (浮動小数点の場合はまず列挙のベースとなる型に変換されます) は、変換後の列挙のすべての列挙子を保持するのに十分大きな最小のビットフィールドに収まるであろう場合、範囲内です)。 そのような変換の後の値はその列挙に対して定義された名前付き列挙子のいずれともと等しくないかもしれないことに注意してください。

enum access_t { read = 1, write = 2, exec = 4 }; // 列挙子: 1, 2, 4。 範囲: 0〜7。
access_t rwe = static_cast<access_t>(7);
assert((rwe & read) && (rwe & write) && (rwe & exec));
 
access_t x = static_cast<access_t>(8.0); // 未定義動作 (C++17以上)。
access_t y = static_cast<access_t>(8); // 未定義動作 (C++17以上)。
 
enum foo { a = 0, b = UINT_MAX }; // 範囲: [0, UINT_MAX]。
foo x= foo(-1); // 未定義動作 (C++17以上) (たとえ foo のベースとなる型が unsigned int であっても)。

スコープなし列挙の name は省略できます。 そのような宣言は囲っているスコープに列挙子を導入するだけです。

enum { a, b, c = 0, d = a + 2 }; // a = 0、 b = 1、 c = 0、 d = 2 を定義します。

スコープなし列挙がクラスのメンバのとき、その列挙子はクラスメンバアクセス演算子 . および -> を用いてアクセスすることができます。

struct X
{
    enum direction { left = 'l', right = 'r' };
};
X x;
X* p = &x;
 
int a = X::direction::left; // C++11以上。
int b = X::left;
int c = x.left;
int d = p->left;

スコープ付き列挙

enum struct|class name { enumerator = constexpr , enumerator = constexpr , ... } (1)
enum struct|class name : type { enumerator = constexpr , enumerator = constexpr , ... } (2)
enum struct|class name ; (3)
enum struct|class name : type ; (4)
1) ベースとなる型が int であるスコープ付き列挙型を宣言します (キーワード classstruct は正確に同等です)。
2) ベースとなる型が type であるスコープ付き列挙型を宣言します。
3) ベースとなる型が int であるスコープ付き列挙に対する不透明な列挙の宣言。
4) ベースとなる型が type であるスコープ付き列挙に対する不透明な列挙の宣言。

それぞれの enumerator はその列挙型 (つまり name) の名前付き定数になります。 それらの定数は列挙のスコープ内に含まれ、スコープ解決演算子を用いてアクセスできます。 列挙子の数値を取得するために static_cast を使用することはできますが、スコープ付き列挙子の値から整数型への暗黙の変換はありません。

enum class Color { red, green = 20, blue };
Color r = Color::blue;
switch(r)
{
    case Color::red  : std::cout << "red\n";   break;
    case Color::green: std::cout << "green\n"; break;
    case Color::blue : std::cout << "blue\n";  break;
}
// int n = r; // エラー、スコープ付き列挙から int への変換はありません。
int n = static_cast<int>(r); // OK、 n = 21 です。
(C++11以上)

ベースとなる型が固定されているスコープ付き列挙型とスコープなし列挙型はどちらも、以下の条件がすべて真であれば、リスト初期化用いて、キャストなしで整数から初期化できます。

  • その初期化が直接リスト初期化である。
  • その初期化子リストが単一の要素のみを含む。
  • その列挙がベースとなる型が固定されているスコープ付きまたはスコープなしのいずれかである。
  • その変換が縮小変換でない。

これは、たとえ構造体の値渡し/値返しにペナルティが生じる ABI 上であっても、ベースとなる整数型と同じ既存の呼び出し規約を用いる新しい整数型 (例えば SafeInt) の導入を可能とします。

enum byte : unsigned char {}; // byte は新しい整数型です。
byte b { 42 }; // OK (C++17以上) (直接リスト初期化)。
byte c = { 42 }; // エラー。
byte d = byte{ 42 }; // OK (C++17以上)。 b と同じ値です。
byte e { -1 }; // エラー。
 
struct A { byte b; };
A a1 = { { 42 } }; // エラー。
A a2 = { byte{ 42 } }; // OK (C++17以上)。
 
void f(byte);
f({ 42 }); // エラー。
 
enum class Handle : std::uint32_t { Invalid = 0 };
Handle h { 42 }; // OK (C++17以上)。
(C++17以上)

[編集]

#include <iostream>
 
// 16ビットを取る列挙。
enum smallenum: int16_t
{
    a,
    b,
    c
};
 
 
// color は red (値 0)、 yellow (値 1)、 green (値 20)、または blue (値 21) です。
enum color
{
    red,
    yellow,
    green = 20,
    blue
};
 
// altitude は altitude::high または altitude::low です。
enum class altitude: char
{ 
     high='h',
     low='l', // C++11 では余分なコンマがあっても構いません。
}; 
 
// 定数 d は 0、定数 e は 1、定数 f は 3 です。
enum
{
    d,
    e,
    f = e + 2
};
 
// 列挙型 (スコープ付きとスコープなしの両方) はオーバーロード演算子を持つことができます。
std::ostream& operator<<(std::ostream& os, color c)
{
    switch(c)
    {
        case red   : os << "red";    break;
        case yellow: os << "yellow"; break;
        case green : os << "green";  break;
        case blue  : os << "blue";   break;
        default    : os.setstate(std::ios_base::failbit);
    }
    return os;
}
 
std::ostream& operator<<(std::ostream& os, altitude al)
{
    return os << static_cast<char>(al);
}
 
int main()
{
    color col = red;
    altitude a;
    a = altitude::low;
 
    std::cout << "col = " << col << '\n'
              << "a = "   << a   << '\n'
              << "f = "   << f   << '\n';
}

出力:

col = red
a = l
f = 3

[編集] 欠陥報告

以下の動作変更欠陥報告は以前に発行された C++ 標準に遡って適用されました。

DR 適用先 発行時の動作 正しい動作
CWG 1638 C++14 grammar of opaque enum declaration prohibited use for template specializations nested-name-specifier permitted

[編集] 関連項目