列挙型 [C++]Enumerations (C++)

列挙体は、列挙子と呼ばれる一連の名前付き整数定数で構成されるユーザー定義型です。An enumeration is a user-defined type that consists of a set of named integral constants that are known as enumerators.


この記事にでは、ISO 標準 C++ 言語enum型と、スコープを持つ (または厳密に型指定された)列挙型クラスc++ 11 で導入された型。This article covers the ISO Standard C++ Language enum type and the scoped (or strongly-typed) enum class type which is introduced in C++11. については、パブリック列挙型クラスまたはプライベート列挙型クラス型 c++/cli および C++/cli CX を参照してください列挙型クラスFor information about the public enum class or private enum class types in C++/CLI and C++/CX, see enum class.


// unscoped enum:
enum [identifier] [: type]

// scoped enum:
enum [class|struct]
[identifier] [: type]
// Forward declaration of enumerations  (C++11):
enum A : int; // non-scoped enum must have type specified
enum class B; // scoped enum defaults to int but ...
enum class C : short;  // ... may have any integral underlying type


列挙体に渡す型名。The type name given to the enumeration.

列挙子の基になる型であり、すべての列挙子は同じ型を基にしています。The underlying type of the enumerators; all enumerators have the same underlying type. 任意の整数型を指定できます。May be any integral type.

列挙体に含まれる列挙子のコンマ区切りのリスト。Comma-separated list of the enumerators in the enumeration. スコープ内のすべての列挙子または変数名は一意である必要があります。Every enumerator or variable name in the scope must be unique. ただし、値は複製できます。However, the values can be duplicated. スコープを持たない列挙型、スコープは前後のスコープスコープは、スコープを持つ列挙型で、列挙型リスト自体。In a unscoped enum, the scope is the surrounding scope; in a scoped enum, the scope is the enum-list itself. スコープを持つ列挙型で、一覧可能性がありますを空にする新しい整数型を定義する有効な。In a scoped enum, the list may be empty which in effect defines a new integral type.

このキーワードを使用すると、宣言で、指定した列挙型のスコープは、および識別子提供する必要があります。By using this keyword in the declaration, you specify the enum is scoped, and an identifier must be provided. 使用することも、構造体キーワードの代わりにクラスなど、このコンテキストで意味的に等しい。You can also use the struct keyword in place of class, as they are semantically equivalent in this context.

列挙子のスコープEnumerator scope

列挙型を使用すると、名前付き定数として表される値の範囲 (列挙子) を記述できます。An enumeration provides context to describe a range of values which are represented as named constants and are also called enumerators. 元の C と C++ の列挙型では、修飾なしの列挙子は列挙型が宣言されているスコープ内で可視です。In the original C and C++ enum types, the unqualified enumerators are visible throughout the scope in which the enum is declared. スコープを持つ列挙型では、列挙子の名前は列挙型の名前で修飾する必要があります。In scoped enums, the enumerator name must be qualified by the enum type name. 次の例に、2 種類の列挙型のこの基本的な相違点を示します。The following example demonstrates this basic difference between the two kinds of enums:

namespace CardGame_Scoped
    enum class Suit { Diamonds, Hearts, Clubs, Spades };

    void PlayCard(Suit suit)
        if (suit == Suit::Clubs) // Enumerator must be qualified by enum type
        { /*...*/}

namespace CardGame_NonScoped
    enum Suit { Diamonds, Hearts, Clubs, Spades };

    void PlayCard(Suit suit)
        if (suit == Clubs) // Enumerator is visible without qualification
        { /*...*/

列挙型の各値の名前には、列挙型の値の順序に対応する場所の整数値が割り当てられます。Every name in an enumeration is assigned an integral value that corresponds to its place in the order of the values in the enumeration. 既定では、最初の値には 0、その次の値には 1 などのように割り当てられますが、次に示すように、列挙体の値を明示的に設定することもできます。By default, the first value is assigned 0, the next one is assigned 1, and so on, but you can explicitly set the value of an enumerator, as shown here:

enum Suit { Diamonds = 1, Hearts, Clubs, Spades };

Diamonds 列挙子に値 1 を割り当てます。The enumerator Diamonds is assigned the value 1. 明示的な値を指定しない場合、後続の列挙子は前の列挙子の値に 1 を加えた数値が指定されます。Subsequent enumerators, if they are not given an explicit value, receive the value of the previous enumerator plus one. 前の例では、Hearts の値が 2、Clubs の値が 3 などのようになります。In the previous example, Hearts would have the value 2, Clubs would have 3, and so on.

すべての列挙子は定数として扱われ、スコープ内で一意の名前を指定する必要があります、列挙型(スコープを持たない列挙型) に対して定義されて内、または、 enum自体 (のスコープを持つ列挙型)。Every enumerator is treated as a constant and must have a unique name within the scope where the enum is defined (for unscoped enums) or within the enum itself (for scoped enums). 列挙子の名前に対応する値は一意である必要はありません。The values given to the names do not have to be unique. たとえば、スコープを持たない列挙型 Suit が次のように宣言されているとします。For example, if the declaration of a unscoped enum Suit is this:

enum Suit { Diamonds = 5, Hearts, Clubs = 4, Spades };

この場合、DiamondsHeartsClubsSpades の値はそれぞれ 5、6、4、5 になります。Then the values of Diamonds, Hearts, Clubs, and Spades are 5, 6, 4, and 5, respectively. 5 つが複数回使用されています。これは意図した値と異なる可能性がありますが、それ自体は問題ありません。Notice that 5 is used more than once; this is allowed even though it may not be intended. これらの規則はスコープを持つ列挙型でも同じです。These rules are the same for scoped enums.

キャストの規則Casting rules

スコープを持たない列挙型定数に暗黙的に変換できるintint列挙型の値に暗黙的に変換することはありません。Unscoped enum constants can be implicitly converted to int, but an int is never implicitly convertible to an enum value. 次の例では、handSuit 型でない値を代入しようとするとどうなるかを示します。The following example shows what happens if you try to assign hand a value that is not a Suit:

int account_num = 135692;
Suit hand;
hand = account_num; // error C2440: '=' : cannot convert from 'int' to 'Suit'

変換には、キャストが必要、 intスコープを持つまたは持たない列挙子にします。A cast is required to convert an int to a scoped or unscoped enumerator. ただし、スコープを持たない列挙子はキャストなしで整数値に上位変換できます。However, you can promote a unscoped enumerator to an integer value without a cast.

int account_num = Hearts; //OK if Hearts is in a unscoped enum

このような暗黙の型変換を使用すると、意図しない副作用につながることがあります。Using implicit conversions in this way can lead to unintended side-effects. スコープを持たない列挙型に関連するプログラミング エラーをなくすために役立つように、スコープを持つ列挙型の値は厳密に型指定します。To help eliminate programming errors associated with unscoped enums, scoped enum values are strongly typed. 次の例に示すように、スコープを持つ列挙子は列挙型の名前 (識別子) で修飾する必要があり、暗黙的に変換されることはありません。Scoped enumerators must be qualified by the enum type name (identifier) and cannot be implicitly converted, as shown in the following example:

namespace ScopedEnumConversions
    enum class Suit { Diamonds, Hearts, Clubs, Spades };

    void AttemptConversions()
        Suit hand;
        hand = Clubs; // error C2065: 'Clubs' : undeclared identifier
        hand = Suit::Clubs; //Correct.
        int account_num = 135692;
        hand = account_num; // error C2440: '=' : cannot convert from 'int' to 'Suit'
        hand = static_cast<Suit>(account_num); // OK, but probably a bug!!!

        account_num = Suit::Hearts; // error C2440: '=' : cannot convert from 'Suit' to 'int'
        account_num = static_cast<int>(Suit::Hearts); // OK

hand = account_num; 行では、前に示したように、スコープを持たない列挙型に関連するエラーが発生することに注意してください。Notice that the line hand = account_num; still causes the error that occurs with unscoped enums, as shown earlier. これは、明示的にキャストすることでエラーを回避できます。It is allowed with an explicit cast. ただし、スコープを持つ列挙型を使用しても、次のステートメント、account_num = Suit::Hearts; での変換の試みは、明示的なキャストなしではエラーが発生します。However, with scoped enums, the attempted conversion in the next statement, account_num = Suit::Hearts;, is no longer allowed without an explicit cast.

なしの列挙子の列挙型Enums with no enumerators

Visual Studio 2017 バージョン 15.3 以降(で使用可能な/std:c + + 17)。(正規表現またはスコープを持つ) 列挙型を定義すると、明示的な基になる型となしの列挙子を有効なを他の型に暗黙的な変換を持たない新しい整数型を導入できます。Visual Studio 2017 version 15.3 and later (available with /std:c++17): By defining an enum (regular or scoped) with an explicit underlying type and no enumerators, you can in effect introduce a new integral type that has no implicit conversion to any other type. この型を使用して、その組み込みの基になる型ではなく、暗黙的な変換を不注意による微妙なエラーが発生する可能性を排除できます。By using this type instead of its built-in underlying type, you can eliminate the potential for subtle errors caused by inadvertent implicit conversions.

enum class byte : unsigned char { };

新しい型は、基になる型の正確なコピーし、パフォーマンスが低下せず Abi 間で使用できる意味と同じ呼び出し規約が備わっています。The new type is an exact copy of the underlying type, and therefore has the same calling convention, which means it can be used across ABIs without any performance penalty. キャストは必要ありませんダイレクト リストの初期化を使用して、型の変数が初期化されるときです。No cast is required when variables of the type are initialized by using direct-list initialization. 次の例では、さまざまなコンテキストでない列挙子の列挙型を初期化する方法を示します。The following example shows how to initialize enums with no enumerators in various contexts:

enum class byte : unsigned char { };

enum class E : int { };
E e1{ 0 };
E e2 = E{ 0 };

struct X
    E e{ 0 };
    X() : e{ 0 } { }

E* p = new E{ 0 };

void f(E e) {};

int main()
    f(E{ 0 });
    byte i{ 42 };
    byte j = byte{ 42 };

    // unsigned char c = j; // C2440: 'initializing': cannot convert from 'byte' to 'unsigned char'
    return 0;

関連項目See also

C 列挙体の宣言C Enumeration Declarations