$(DDOC $(DDOC_BLANKLINE ) $(DDOC_BLANKLINE ) $(SPEC_S Enums, $(DDOC_BLANKLINE ) $(HEADERNAV_TOC $(HEADERNAV_SUBITEMS named_enums, Named Enums, $(HEADERNAV_ITEM enum_variables, Enum Variables) $(HEADERNAV_ITEM enum_properties, Enum Properties) $(HEADERNAV_ITEM enum_copying_and_assignment, Enum Copying and Assignment) ) $(HEADERNAV_SUBITEMS anonymous_enums, Anonymous Enums, $(HEADERNAV_ITEM single_member, Single Member Syntax) ) $(HEADERNAV_ITEM manifest_constants, Manifest Constants) ) $(DDOC_BLANKLINE ) $(GRAMMAR $(GNAME EnumDeclaration): $(D enum) $(GLINK_LEX Identifier) $(GLINK EnumBody) $(D enum) $(GLINK_LEX Identifier) $(D :) $(GLINK EnumBaseType) $(GLINK EnumBody) $(GLINK AnonymousEnumDeclaration) $(DDOC_BLANKLINE ) $(GNAME EnumBaseType): $(GLINK2 type, Type) $(DDOC_BLANKLINE ) $(GNAME EnumBody): $(D {) $(GLINK EnumMembers) $(D }) $(D ;) $(DDOC_BLANKLINE ) $(GNAME EnumMembers): $(GLINK EnumMember) $(GLINK EnumMember) $(D ,) $(GLINK EnumMember) $(D ,) $(GSELF EnumMembers) $(DDOC_BLANKLINE ) $(GNAME EnumMember): $(GLINK EnumMemberAttributes)$(OPT ) $(GLINK_LEX Identifier) $(GLINK EnumMemberAttributes)$(OPT ) $(GLINK_LEX Identifier) $(D =) $(ASSIGNEXPRESSION ) $(DDOC_BLANKLINE ) $(GNAME EnumMemberAttributes): $(GLINK EnumMemberAttribute) $(GLINK EnumMemberAttribute) $(GSELF EnumMemberAttributes) $(DDOC_BLANKLINE ) $(GNAME EnumMemberAttribute): $(GLINK2 attribute, DeprecatedAttribute) $(GLINK2 attribute, UserDefinedAttribute) $(D @)$(LINK2 attribute.html#disable, $(D disable)) ) $(GRAMMAR $(GNAME AnonymousEnumDeclaration): $(D enum) $(D :) $(GLINK EnumBaseType) $(D {) $(GLINK EnumMembers) $(D }) $(D enum) $(D {) $(GLINK AnonymousEnumMembers) $(D }) $(DDOC_BLANKLINE ) $(GNAME AnonymousEnumMembers): $(GLINK AnonymousEnumMember) $(GLINK AnonymousEnumMember) $(D ,) $(GLINK AnonymousEnumMember) $(D ,) $(GSELF AnonymousEnumMembers) $(DDOC_BLANKLINE ) $(GNAME AnonymousEnumMember): $(GLINK EnumMember) $(GLINK EnumMemberAttributes)$(OPT ) $(GLINK2 type, Type) $(GLINK_LEX Identifier) $(D =) $(ASSIGNEXPRESSION ) ) $(DDOC_BLANKLINE ) $(P Enum declarations are used to define a group of constants. ) $(DDOC_BLANKLINE )

$(LNAME2 named_enums, Named Enums)

$(DDOC_BLANKLINE ) $(P Named enums are used to declare related constants and group them by giving them a unique type. The $(GLINK EnumMembers) are declared in the scope of the named enum. The named enum declares a new type, and all the $(I EnumMembers) have that type. ) $(DDOC_BLANKLINE ) $(P This defines a new type $(CODE X) which has values $(CODE X.A=0), $(CODE X.B=1), $(CODE X.C=2):) $(DDOC_BLANKLINE ) $(D_CODE $(D_KEYWORD enum) X { A, B, C } $(D_COMMENT // named enum )) $(DDOC_BLANKLINE ) $(DDOC_BLANKLINE ) $(P If the $(GLINK EnumBaseType) is not explicitly set, and the first $(I EnumMember) has an AssignExpression, it is set to the type of that AssignExpression. Otherwise, it defaults to type $(CODE int).) $(UL $(LI A named enum member can be implicitly cast to its $(I EnumBaseType).) $(LI An $(I EnumBaseType) instance cannot be implicitly cast to a named enum type. ) ) $(SPEC_RUNNABLE_EXAMPLE_FAIL $(D_CODE $(D_KEYWORD int) i; $(D_KEYWORD enum) Foo { E } Foo f; i = f; $(D_COMMENT // OK )f = i; $(D_COMMENT // error )f = $(D_KEYWORD cast)(Foo)i; $(D_COMMENT // OK )f = 0; $(D_COMMENT // error )f = Foo.E; $(D_COMMENT // OK )) ) $(DDOC_BLANKLINE ) $(P A named enum member does not have an individual $(I Type).) $(DDOC_BLANKLINE ) $(P The value of an $(GLINK EnumMember) is given by its AssignExpression if present. If there is no AssignExpression and it is the first $(I EnumMember), its value is converted to $(GLINK EnumBaseType) from 0. If there is no AssignExpression and it is not the first $(I EnumMember), it is given the value of the previous $(I EnumMember)+1:) $(UL $(LI If the value of the previous $(I EnumMember) is $(GLINK EnumBaseType).max, it is an error. This prevents value overflow. It is an error if the previous member cannot be compared with EnumBaseType.max at compile-time.) $(LI It is an error if the base type does not define a compile-time evaluable +1 operation.) $(LI If the value of the previous $(I EnumMember)+1 is the same as the value of the previous $(I EnumMember), it is an error. (This can happen with floating point types). ) ) $(SPEC_RUNNABLE_EXAMPLE_FAIL $(D_CODE $(D_KEYWORD enum) E : $(D_KEYWORD char) { a, b = $(D_KEYWORD char).max, c $(D_COMMENT // overflow )} $(D_KEYWORD static) $(D_KEYWORD assert)(E.a == 0); ) ) $(DDOC_BLANKLINE ) $(P All $(I EnumMember)s are in scope for the AssignExpressions. ) $(DDOC_BLANKLINE ) $(SPEC_RUNNABLE_EXAMPLE_FAIL $(D_CODE $(D_KEYWORD enum) A = 3; $(D_KEYWORD enum) B { A = A $(D_COMMENT // error, circular reference )} $(D_KEYWORD enum) C { A = B, $(D_COMMENT // A = 4 ) B = D, $(D_COMMENT // B = 4 ) C = 3, $(D_COMMENT // C = 3 ) D $(D_COMMENT // D = 4 )} $(D_KEYWORD enum) E : C { E1 = C.D, E2 $(D_COMMENT // error, C.D is C.max )} ) ) $(DDOC_BLANKLINE ) $(P An empty enum body signifies an opaque enum - the enum members are unknown.) $(D_CODE $(D_KEYWORD enum) X; $(D_COMMENT // opaque enum )writeln(X.init); $(D_COMMENT // error: enum X is opaque and has no default initializer )) $(DDOC_BLANKLINE )

$(LEGACY_LNAME2 enum_default_initializer, enum_variables, Enum Variables)

$(DDOC_BLANKLINE ) $(P A variable can be of named enum type. The default initializer is the first member defined for the enum type. ) $(DDOC_BLANKLINE ) $(SPEC_RUNNABLE_EXAMPLE_RUN $(D_CODE $(D_KEYWORD enum) X { A=3, B, C } X x; $(D_KEYWORD assert)(x == X.A); x |= X.B; $(D_KEYWORD assert)(x & X.A); ) ) $(DDOC_BLANKLINE ) $(P The result type of a binary operation performed when the operands have different types is defined $(DDSUBLINK spec/type, enum-ops, here).) $(DDOC_BLANKLINE ) $(P See also: $(DDSUBLINK spec/statement, final-switch-statement, final switch).) $(DDOC_BLANKLINE )

$(LNAME2 enum_properties, Enum Properties)

$(DDOC_BLANKLINE ) $(P Enum properties only exist for named enums. ) $(DDOC_BLANKLINE ) $(TABLE $(CAPTION Named Enum Properties) $(TROW $(D .init), First enum member value) $(TROW $(D .min), Smallest enum member value) $(TROW $(D .max), Largest enum member value) $(TROW $(D .sizeof), Size of storage for an enumerated value) ) $(DDOC_BLANKLINE ) $(P For example:) $(DDOC_BLANKLINE ) $(D_CODE $(D_KEYWORD enum) X { A=3, B=1, C=4, D, E=2 } X.init $(D_COMMENT // is X.A )X.min $(D_COMMENT // is X.B )X.max $(D_COMMENT // is X.D )X.sizeof $(D_COMMENT // is same as int.sizeof )) $(DDOC_BLANKLINE ) $(P The $(GLINK EnumBaseType) of named enums must support comparison in order to compute the $(CODE .max) and $(CODE .min) properties. ) $(DDOC_BLANKLINE )

$(LNAME2 enum_copying_and_assignment, Enum Copying and Assignment)

$(DDOC_BLANKLINE ) $(P A named enum type never has a $(DDSUBLINK spec/struct, struct-copy-constructor, copy constructor), $(DDSUBLINK spec/struct, struct-postblit, postblit), or $(DDSUBLINK spec/struct, assign-overload, identity assignment overload), even if one is defined by its $(GLINK EnumBaseType).) $(DDOC_BLANKLINE ) $(P When copying a named enum value whose base type is a struct with a copy constructor, the copy constructor is not called:) $(DDOC_BLANKLINE ) $(SPEC_RUNNABLE_EXAMPLE_RUN $(D_CODE $(D_KEYWORD struct) S { $(D_KEYWORD this)($(D_KEYWORD ref) S rhs) { $(D_KEYWORD assert)(0); } } $(D_KEYWORD enum) E : S { A = S.init } $(D_KEYWORD void) main() { E e1; E e2 = e1; $(D_COMMENT // ok - copy constructor not called )} ) ) $(DDOC_BLANKLINE ) $(P When copying a named enum value whose base type is a struct with a postblit, the postblit is not called:) $(DDOC_BLANKLINE ) $(SPEC_RUNNABLE_EXAMPLE_RUN $(D_CODE $(D_KEYWORD struct) S { $(D_KEYWORD this)($(D_KEYWORD this)) { $(D_KEYWORD assert)(0); } } $(D_KEYWORD enum) E : S { A = S.init } $(D_KEYWORD void) main() { E e1; E e2 = e1; $(D_COMMENT // ok - postblit not called )} ) ) $(DDOC_BLANKLINE ) $(P When assigning a named enum value to another object of the same type, if the base type of those values is a struct with an identity assignment overload, the identity assignment overload is not called:) $(DDOC_BLANKLINE ) $(SPEC_RUNNABLE_EXAMPLE_RUN $(D_CODE $(D_KEYWORD struct) S { $(D_KEYWORD void) opAssign(S rhs) { $(D_KEYWORD assert)(0); } } $(D_KEYWORD enum) E : S { A = S.init } $(D_KEYWORD void) main() { E e1, e2; e2 = e1; $(D_COMMENT // ok - opAssign not called )} ) ) $(DDOC_BLANKLINE ) $(DDOC_BLANKLINE )

$(LNAME2 anonymous_enums, Anonymous Enums)

$(DDOC_BLANKLINE ) $(P If the enum $(I Identifier) is not present, then the enum is an $(I anonymous enum), and the $(GLINK EnumMembers) are declared in the scope the $(GLINK EnumDeclaration) appears in. No new type is created. ) $(DDOC_BLANKLINE ) $(P The $(I EnumMembers) can have different types. Those types are given by the first of: ) $(DDOC_BLANKLINE ) $(OL $(LI The $(I Type), if present. Types are not permitted when an $(GLINK EnumBaseType) is present.) $(LI The $(I EnumBaseType), if present.) $(LI The type of the $(I AssignExpression), if present.) $(LI The type of the previous $(I EnumMember), if present.) $(LI $(CODE int)) ) $(DDOC_BLANKLINE ) $(DDOC_BLANKLINE ) $(D_CODE $(D_KEYWORD enum) { A, B, C } $(D_COMMENT // anonymous enum )) $(DDOC_BLANKLINE ) $(P Defines the constants A=0, B=1, C=2, all of type int.) $(DDOC_BLANKLINE ) $(P Enums must have at least one member. ) $(DDOC_BLANKLINE ) $(P The value of an $(I EnumMember) is given by its AssignExpression if present. If there is no AssignExpression and it is the first $(I EnumMember), its value is the $(CODE .init) property of the $(I EnumMember)'s type. If there is no AssignExpression and it is not the first $(I EnumMember), it is given the value of the previous $(I EnumMember)+1:) $(UL $(LI If the value of the previous $(I EnumMember) is the .max property of the previous $(I EnumMember)'s type, it is an error. This prevents value overflow. It is an error if the previous member cannot be compared with its .max property at compile-time.) $(LI It is an error if the type of the previous member does not define a compile-time evaluable +1 operation.) $(LI If the value of the previous $(I EnumMember)+1 is the same as the value of the previous $(I EnumMember), it is an error. (This can happen with floating point types). ) ) $(P All $(I EnumMember)s are in scope for the AssignExpressions. ) $(DDOC_BLANKLINE ) $(D_CODE $(D_KEYWORD enum) { A, B = 5+7, C, D = 8+C, E } ) $(DDOC_BLANKLINE ) $(P Sets A=0, B=12, C=13, D=21, and E=22, all of type int.) $(DDOC_BLANKLINE ) $(D_CODE $(D_KEYWORD enum) : $(D_KEYWORD long) { A = 3, B } ) $(DDOC_BLANKLINE ) $(P Sets A=3, B=4 all of type long.) $(DDOC_BLANKLINE ) $(D_CODE $(D_KEYWORD enum) : string { A = $(D_STRING "hello"), B = $(D_STRING "betty"), C $(D_COMMENT // error, cannot add 1 to "betty" )} ) $(DDOC_BLANKLINE ) $(D_CODE $(D_KEYWORD enum) { A = 1.2f, $(D_COMMENT // A is 1.2f of type float ) B, $(D_COMMENT // B is 2.2f of type float ) $(D_KEYWORD int) C = 3, $(D_COMMENT // C is 3 of type int ) D $(D_COMMENT // D is 4 of type int )} ) $(DDOC_BLANKLINE )

$(LNAME2 single_member, Single Member Syntax)

$(DDOC_BLANKLINE ) $(P If there is only one member of an anonymous enum, the { } can be omitted. Gramatically speaking, this is an $(GLINK2 declaration, AutoDeclaration). ) $(DDOC_BLANKLINE ) $(D_CODE $(D_KEYWORD enum) i = 4; $(D_COMMENT // i is 4 of type int )$(D_KEYWORD enum) $(D_KEYWORD long) l = 3; $(D_COMMENT // l is 3 of type long )) $(DDOC_BLANKLINE )

$(LNAME2 manifest_constants, Manifest Constants)

$(DDOC_BLANKLINE ) $(P Enum members are manifest constants, which exist only at compile-time.) $(DDOC_BLANKLINE ) $(P Manifest constants are not lvalues, meaning their address cannot be taken. They exist only in the memory of the compiler.) $(DDOC_BLANKLINE ) $(D_CODE $(D_KEYWORD enum) size = $(D_KEYWORD __traits)(classInstanceSize, Foo); $(D_COMMENT // evaluated at compile-time )) $(DDOC_BLANKLINE ) $(P The initializer for a manifest constant is evaluated using compile time function evaluation.) $(DDOC_BLANKLINE ) $(D_CODE $(D_KEYWORD template) Foo(T) { $(D_COMMENT // Not bad, but the 'size' variable will be located in the executable. ) $(D_KEYWORD const) size_t size = T.sizeof; $(D_COMMENT // evaluated at compile-time ) $(D_COMMENT // ... use of 'size' at compile time ... )} $(D_KEYWORD template) Bar(T) { $(D_COMMENT // Better, the manifest constant has no runtime location in the executable. ) $(D_KEYWORD enum) size_t size = T.sizeof; $(D_COMMENT // evaluated at compile-time ) $(D_COMMENT // ... use of 'size' at compile time ... ) $(D_COMMENT // Taking the address of Foo!T.size also causes it to go into the exe file. ) $(D_KEYWORD auto) p = &Foo!T.size; } ) $(DDOC_BLANKLINE ) $(DDOC_BLANKLINE ) $(SPEC_SUBNAV_PREV_NEXT interface, Interfaces, const3, Type Qualifiers) ) )