英語版
このページの英語版を見る

列挙型

EnumDeclaration:
    enum Identifier EnumBody
    enum Identifier : EnumBaseType EnumBody
    AnonymousEnumDeclaration
EnumBaseType: Type
EnumBody: { EnumMembers } ;
EnumMembers: EnumMember EnumMember , EnumMember , EnumMembers
EnumMember: EnumMemberAttributesopt Identifier EnumMemberAttributesopt Identifier = AssignExpression
EnumMemberAttributes: EnumMemberAttribute EnumMemberAttribute EnumMemberAttributes
EnumMemberAttribute: DeprecatedAttribute UserDefinedAttribute @disable
AnonymousEnumDeclaration:
    enum : EnumBaseType { EnumMembers }
    enum { AnonymousEnumMembers }
AnonymousEnumMembers: AnonymousEnumMember AnonymousEnumMember , AnonymousEnumMember , AnonymousEnumMembers
AnonymousEnumMember: EnumMember EnumMemberAttributesopt Type Identifier = AssignExpression

列挙型宣言は、定数のグループを定義するために使用される。

列挙型(Named Enum)

名前付き列挙型" は、関連する定数を宣言するために使用される。 定数を宣言し、一意の型を与えてグループ化するために使用される。 EnumMembersは、名前付き列挙型のスコープで宣言される。名前付き enumは新しい型を宣言し、すべてのEnumMembersはその型を持つ。

これは新しい型X を定義している。 X.A=0 X.B=1 X.C=2 を持つ:

enum X { A, B, C }  // 名前付き列挙型

EnumBaseTypeが明示的に設定されておらず、最初の EnumMemberが AssignExpressionを持つ場合、その型が設定される。 設定される。そうでない場合、デフォルトは 型int に設定される。

int i;

enum Foo { E }
Foo f;
i = f;           // OK
f = i;           // エラー
f = cast(Foo)i;  // OK
f = 0;           // エラー
f = Foo.E;       // OK

名前付き列挙型メンバは個別の型を持たない。

EnumMemberの値は、AssignExpression が存在する場合は、その AssignExpression で指定される。 AssignExpression がなく、それが最初のEnumMember である場合、その値は EnumMember 型に変換される、 その値は0 からEnumBaseTypeに変換される。 AssignExpressionがなく、最初のEnumMember でもない場合、その値は直前の EnumBaseType の値に変換される、 には、直前のEnumMember+1 の値が与えられる:

enum E : char
{
    a,
    b = char.max,
    c // オーバーフロー
}

static assert(E.a == 0);

すべてのEnumMemberは AssignExpressionsのスコープ内にある。

enum A = 3;
enum B
{
    A = A // エラー、循環参照
}
enum C
{
    A = B,  // A = 4
    B = D,  // B = 4
    C = 3,  // C = 3
    D       // D = 4
}
enum E : C
{
    E1 = C.D,
    E2      // エラー、C.DはC.maxである
}

空の列挙型本体は、不透明な列挙型を意味する。

enum X;          // 不透明な列挙型
writeln(X.init); // エラー: 列挙型Xは不透明であり、デフォルトのイニシャライザを持たない

列挙型変数

変数は名前付き列挙型にすることができる。 デフォルトのイニシャライザは、enum型で定義された最初のメンバである。

enum X { A=3, B, C }
X x;
assert(x == X.A);
x |= X.B;
assert(x & X.A);

オペランドの型が異なる場合に実行される二項演算の結果型は、ここで定義される。 ここで定義される。

こちらも参照のこと: final switch.

列挙型プロパティ

列挙型プロパティは名前付き列挙型にのみ存在する。

名前付き列挙型プロパティ
.init最初の列挙型メンバーの値
.min最小列挙型値
.max最大の列挙型メンバ値
.sizeof列挙値のストレージサイズ

例:":

enum X { A=3, B=1, C=4, D, E=2 }
X.init   // is X.A
X.min    // is X.B
X.max    // is X.D
X.sizeof // int.sizeofと同じである

名前付き列挙型のEnumBaseTypeは比較をサポートしなければならない。 .max .min をサポートしなければならない。

列挙型のコピーと代入

名前付き列挙型はコピーコンストラクタを持たない。 コピーコンストラクタを持たない、 ポストブリット ID 代入のオーバーロードを持つことはない、 たとえEnumBaseType で定義されていてもである。

基本型がstruct である名前付き列挙型をコピーする場合、コピーコンストラクタは呼び出されない。 である名前付き列挙値をコピーする場合、コピーコンストラクタは呼び出されない:

struct S
{
    this(ref S rhs) { assert(0); }
}

enum E : S { A = S.init }

void main()
{
    E e1;
    E e2 = e1; // OK - コピーコンストラクタが呼び出されていない
}

基底型がstruct である名前付き列挙型をコピーする場合、コピーコンストラクタは呼び出されない。 を持つ名前付き列挙値をコピーする場合、ポストブリットは呼び出されない:

struct S
{
    this(this) { assert(0); }
}

enum E : S { A = S.init }

void main()
{
    E e1;
    E e2 = e1; // OK - postblitが呼び出されない
}

名前付き列挙型値を同じ型の別のオブジェクトに代入するとき、それらのオブジェクトの基底型がポストブリットである場合、ポストブリットは呼び出されない。 名前付き列挙値を同じ型の別のオブジェクトに代入するとき、それらの値の基本型がstruct 、identity代入オーバーロードがある場合、identity代入オーバーロードは呼び出されない。 を持つ場合、identity assignment overload は呼び出されない:

struct S
{
    void opAssign(S rhs) { assert(0); }
}

enum E : S { A = S.init }

void main()
{
    E e1, e2;
    e2 = e1; // OK - opAssignが呼び出されない
}

匿名列挙型

列挙型識別子が存在しない場合、その列挙型は匿名列挙型である。 は匿名列挙型であり、EnumMembersは EnumDecifier のスコープで宣言される。 が宣言される。 新しい型は作成されない。

EnumMembersは異なる型を持つことができる。 それらの型は、of.EnumMembersの最初の部分で指定される:

  1. 型がある場合は、その型によって与えられる。EnumBaseTypeが存在する場合、型は許されない。 EnumBaseTypeが存在する場合、型は許可されない。
  2. EnumBaseType が存在する場合。
  3. AssignExpression の型(存在する場合)。
  4. 前のEnumMember の型(存在する場合)。
  5. int
enum { A, B, C }  // anonymous enum

定数A=0, B=1, C=2、すべてint 型を定義する。

列挙型は少なくとも1つのメンバを持たなければならない。

EnumMemberの値は、AssignExpressionが存在すれば、それによって与えられる。 AssignExpressionがなく、それが最初のEnumMemberである場合、その値は、 .init その値はEnumMemberの"@property"型である。 AssignExpressionがなく、それが最初のEnumMember でない場合、その値は前の EnumMember の値になる、 には、前のEnumMember+1 の値が与えられる:

すべてのEnumMemberは AssignExpressionsのスコープ内にある。

enum { A, B = 5+7, C, D = 8+C, E }

A=0、B=12、C=13、D=21、E=22、すべてint

enum : long { A = 3, B }

A=3、B=4、すべてlong

enum : string
{
    A = "hello",
    B = "betty",
    C     // エラー、"betty"に1を追加できない
}
enum
{
    A = 1.2f,  // Aはfloat型の1.2fである
    B,         // Bはfloat型の2.2fである
    int C = 3, // Cはint型の3である
    D          // Dはint型の4である
}

単一メンバー構文

無名列挙型のメンバが1つだけの場合、{ } は省略できる。 を省略できる。文法的に言えば、これは自動宣言である。

enum i = 4;      // iはint型の4である
enum long l = 3; // lはlong型の3である

マニフェスト定数

列挙型定数は、コンパイル時にのみ存在する。

マニフェスト定数はl値ではない。 を取ることはできない。 これらはコンパイラのメモリ内にのみ存在する。

enum size = __traits(classInstanceSize, Foo);  // コンパイル時に評価される

マニフェスト定数のイニシャライザーは、コンパイル時の関数評価によって評価される。

template Foo(T)
{
    // 悪くないが、'size'変数は実行ファイルに配置される。
    const size_t size = T.sizeof;       // コンパイル時に評価される

    // ... コンパイル時に'size'を使用する ...
}

template Bar(T)
{
    // Better, マニフェスト定数は実行可能ファイル内に実行時の場所を持たない。
    enum size_t size = T.sizeof;        // コンパイル時に評価される

    // ... コンパイル時に'size'を使用する。 ...

    // Foo!T.sizeのアドレスを取ると、それが実行ファイルに入る。
    auto p = &Foo!T.size;
}