Better Enums 0.8.0

The best way to get started with Better Enums is to read the project page and browse the commented examples. This page gives reference documentation.

The following declaration

#include <enum.h>
ENUM(Enum, underlying_type, A, B, C);

generates a new type Enum. It is notionally similar to the type created by this declaration:

enum class Enum : underlying_type {A, B, C};

that is, it is an enumerated type with constants Enum::A, Enum::B, and Enum::C, and is represented in memory by an integer of type underlying_type. Just like with a built-in enum class, it is possible to specify numeric values and aliases for constants:

ENUM(Enum, underlying_type, A = 1, B, C, D = A);

Constant values are assigned by the compiler by exactly the same rules as for a built-in enum, so in the above example, Enum::A == 1, Enum::B == 2, Enum::C == 3, and Enum::D == 1.

Member index

Internal enumerated type index

typename Enum::_Enumerated

The declared type Enum is built around an internal C++ enumeration. Notionally,

ENUM(Enum, int, A, B, C);

produces

class Enum {
    ...
  public:
    enum _Enumerated : int {A, B, C};
    ...
};

_Enumerated is simply the name of the internal enumeration. The user should not use this type name directly, but it is referred to in the rest of the documentation. The name is exposed because a literal Enum::A is not a value of type Enum, but a value of type Enum::_Enumerated, which is convertible to Enum, in most cases implicitly.

Note that _Enumerated is not a C++11 enum class.

implicit constructor constexpr Enum(_Enumerated)

A converting constructor for promoting values of type _Enumerated to values of type Enum. As mentioned above, this typically happens automatically when you write a literal constant such as Enum::A in a context where a value of type Enum is expected. For example:

void do_something(Enum value) { ... }

do_something(Enum::A);  // converted silently

global unary constexpr operator +(_Enumerated)

For use when the compiler does not choose the implicit constructor above. For example:

(Enum::A).to_string()

This expression does not compile because Enum::A is not an object, and the compiler does not promote it. The promotion can be forced:

(+Enum::A).to_string()

This is easier to maintain than writing out a call to the converting constructor:

((Enum)Enum::A).to_string()

casting constexpr operator _Enumerated() const

Enables implicit conversion of Enum values down to _Enumerated. The only purpose of this is to make Enum values directly usable in switch statements for compiler-supported case checking:

switch(enum_value) {
    case Enum::A: ...; break;
    case Enum::B: ...; break;
    case Enum::C: ...; break;
}

It is, unfortunately, a hole in the type safety of Enum, since it allows implicit conversions to integral types (Enum to _Enumerated, then _Enumerated to an integer). The user should not rely on such conversions. They will probably be eliminated in the future, perhaps by replacing this conversion with a conversion to an enum class.

Underlying integral type index

typename Enum::_Integral

An alias for the underlying type that Enum was declared with. For example, if the declaration is

ENUM(Enum, uint32_t, A, B, C);

Then Enum::_Integral is the same as uint32_t.

static constexpr Enum _from_integral(_Integral)

Checked cast from a numeric value to an enum value. The function checks that there is an enum constant with the given value. If not, it throws std::runtime_error. The check takes time linear in the number of constants in Enum.

static constexpr Enum _from_integral_unchecked(_Integral)

Unchecked cast from a numeric value to an enum value. The function assumes that there is an enum constant with the given value. The user has to ensure that this assumption holds. If not, the behavior of subsequent operations on the returned enum value is undefined.

member constexpr _Integral enum_value.to_integral() const

Returns the numeric representation of an enum value.

static constexpr bool _is_valid(_Integral)

Checks that the given numeric value represents one of the constants in Enum, as in _from_integral. Complexity is linear in the number of constants.

invariant sizeof(Enum) == sizeof(Enum::_Integral)

invariant alignof(Enum) == alignof(Enum::_Integral)

String conversions index

static constexpr Enum _from_string(const char*)

Returns the enum constant given by the string. For example:

Enum::_from_string("A") == Enum::A

Complexity is linear in the number of constants multiplied by the length of the longest constant name. If the string does not name a constant, throws std::runtime_error.

static constexpr Enum _from_string_nocase(const char*)

The same as above, but lookup is case-insensitive.

member constexpr const char* enum_value.to_string() const

Returns the string representation of enum value on which the method is called. If multiple constants have the same numeric value, the string returned can be the representation any of the constants. Complexity is linear in the number of constants. If the string does not name a constant, throws std::runtime_error.

static constexpr const char *_name

The name of the type, i.e., for

ENUM(Enum, int, A, B, C);

Enum::_name == "Enum"

static constexpr bool _is_valid(const char*)

Checks that the given string is the name of one of the constants in Enum, as in _from_string, with the same complexity.

static constexpr bool _is_valid_nocase(const char*)

The same as above, but corresponding to _from_string_nocase.

Iteration index

static constexpr _ValueIterable values

An iterable container with all the defined constant values, in declaration order. Suitable for use with range-based for loops:

for (Enum value : Enum::_values) {
    // Will iterate over Enum::A, Enum::B, Enum::C
}

class _ValueIterable::iterator

An iterator over defined constant values with a constexpr dereference operator. Can be created explicitly by the constexpr expressions

Enum::_values::begin()
Enum::_values::end()

static constexpr _NameIterable names

An iterable container with the names of the defined constant values, in declaration order. Suitable for use with range-based for loops:

for (const char *name : Enum::_names) {
    // Will iterate over "A", "B", "C"
}

class _NameIterable::iterator

An iterator over defined constant names with a constexpr dereference operator. Can be created explicitly by the constexpr expressions

Enum::_names::begin()
Enum::_names::end()

Range properties index

static constexpr _Enumerated _first

The first defined constant. For example, in

ENUM(Enum, int, A = 1, B = 5, C = 0);

Enum::_first == Enum::A

static constexpr _Enumerated _last

The last defined constant, i.e. Enum::C in the above example.

static constexpr _Enumerated _min

The defined constant with the smallest numeric value, i.e. Enum::C in the above example.

static constexpr _Enumerated _max

The defined constant with the greatest numeric value, i.e. Enum::B in the above example.

static constexpr size_t _size

The number of constants defined, i.e. 3 in the above example.

static constexpr _Integral _span

The numeric span of the constants defined, i.e. _max - _min + 1, which is 6 in the above example.

Comparisons index

member constexpr bool operator ==(const Enum&) const

member constexpr bool operator ==(_Enumerated) const

member constexpr bool operator !=(const Enum&) const

member constexpr bool operator !=(_Enumerated) const

member constexpr bool operator <(const Enum&) const

member constexpr bool operator <(_Enumerated) const

member constexpr bool operator <=(const Enum&) const

member constexpr bool operator <=(_Enumerated) const

member constexpr bool operator >(const Enum&) const

member constexpr bool operator >(_Enumerated) const

member constexpr bool operator >=(const Enum&) const

member constexpr bool operator >=(_Enumerated) const

These define an ordering on values of types Enum and Enum::_Enumerated. The ordering is according to the values' numeric representations. That means that two values that have been aliased will compare equal. Direct comparisons with all other types are forbidden; this is enforced by deleted comparison operators for all other types.

Additional type safety index

default constructor Enum() = delete

The default constructor is deleted to encourage initialization with valid values only and to avoid undefined states. See example/6-traits.cc for an example of how to add an explicit notion of default value.

invariant no arithmetic

Arithmetic operators are explicitly deleted.

invariant no implicit conversion from integers