次の方法で共有


C++ 列挙体の宣言

列挙体は、列挙子と呼ばれる一連の名前付き整数定数で構成されるユーザー定義型です。

注意

ここでは、ISO 標準 C++ 言語の enum 型とスコープを持つ (または厳密に型指定された) enum class 型について説明します。列挙型クラスは C++11 で導入されました。C++/CLI および C++/CX の public enum class 型や private enum class 型については、「enum クラス (C++ コンポーネント拡張)」を参照してください。

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

{enum-list}; 

// scoped enum:
enum [class|struct] 
[identifier] [: type] 
{enum-list};

パラメーター

  • identifier
    列挙体に渡す型名。

  • type
    列挙子の基になる型であり、すべての列挙子は同じ型を基にしています。 任意の整数型を指定できます。

  • enum-list
    列挙体に含まれる列挙子のコンマ区切りのリスト。 スコープ内のすべての列挙子または変数名は一意である必要があります。 ただし、値は複製できます。 スコープを持たない列挙型では、スコープは親のスコープです。スコープを持つ列挙型では、スコープは enum-list 自体のスコープです。

  • class
    宣言内でこのキーワードを使用することにより、列挙型がスコープを持ち、identifier が提供される必要があることを指定します。 class の代わりに、このコンテキストで意味的に同等な struct キーワードを使用することもできます。

解説

列挙型を使用すると、名前付き定数として表される値の範囲 (列挙子) を記述できます。 元の C と C++ の列挙型では、修飾なしの列挙子は列挙型が宣言されているスコープ内で可視です。 スコープを持つ列挙型では、列挙子の名前は列挙型の名前で修飾する必要があります。 次の例に、2 種類の列挙型のこの基本的な相違点を示します。

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
        { /*...*/
        }
    }
}

列挙型の各値の名前には、列挙型の値の順序に対応する場所の整数値が割り当てられます。 既定では、最初の値には 0、その次の値には 1 などのように割り当てられますが、次に示すように、列挙体の値を明示的に設定することもできます。

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

Diamonds 列挙子に値 1 を割り当てます。 明示的な値を指定しない場合、後続の列挙子は前の列挙子の値に 1 を加えた数値が指定されます。 前の例では、Hearts の値が 2、Clubs の値が 3 などのようになります。

すべての列挙子は定数として扱われ、enum が定義されているスコープ内で (スコープを持たない列挙型の場合)、または列挙型自体のスコープ内で (スコープを持つ列挙型の場合)、列挙子の名前は一意である必要があります。 列挙子の名前に対応する値は一意である必要はありません。 たとえば、スコープを持たない列挙型 Suit が次のように宣言されているとします。

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

この場合、Diamonds、Hearts、Clubs、Spades の値はそれぞれ 5、6、4、5 になります。 5 つが複数回使用されています。これは意図した値と異なる可能性がありますが、それ自体は問題ありません。 これらの規則はスコープを持つ列挙型でも同じです。

キャストの規則

スコープを持たない列挙型の定数が暗黙的に int に変換されることはありますが、int が列挙型の値に暗黙的に変換されることはありません。 次の例では、hand に Suit 型でない値を代入しようとするとどうなるかを示します。

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

スコープを持つまたは持たない列挙子に int を変換するには、キャストが必要です。 ただし、スコープを持たない列挙子はキャストなしで整数値に上位変換できます。

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

このような暗黙の型変換を使用すると、意図しない副作用につながることがあります。 スコープを持たない列挙型に関連するプログラミング エラーをなくすために役立つように、スコープを持つ列挙型の値は厳密に型指定します。 次の例に示すように、スコープを持つ列挙子は列挙型の名前 (識別子) で修飾する必要があり、暗黙的に変換されることはありません。

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; 行では、前に示したように、スコープを持たない列挙型に関連するエラーが発生することに注意してください。 これは、明示的にキャストすることでエラーを回避できます。 ただし、スコープを持つ列挙型を使用しても、次のステートメント、account_num = Suit::Hearts; での変換の試みは、明示的なキャストなしではエラーが発生します。

参照

関連項目

C 列挙体の宣言

C++ キーワード