Better Enums

Reflective compile-time enums for C++

Open-source under the BSD license

Version 0.11.3

To install, just add enum.h to your project.

Visit the GitHub repo for issues, feedback, and the latest development.

Download enum.h GitHub

Opt-in features

Better Enums has two opt-in features. They are both "good," but they either hurt compilation time or break compatibility with C++98, so they are disabled by default. Read this page if you want to enable them.

Contents

Default constructors

Better Enums generate with inaccessible (private or deleted) default constructors. This is meant to help control where in your program Better Enums values are introduced, and thus ensure that only valid, properly initialized enum values are ever created.

If you want Better Enums to have a default constructor, you can do something like the following:

#define BETTER_ENUMS_DEFAULT_CONSTRUCTOR(Enum) \
  public:                                      \
    Enum() = default;

#include <enum.h>

You can put this in its own header file, and include that header file instead of including enum.h directly.

Compile-time name trimming

This makes _to_string and _names constexpr, i.e. "full" constexpr mode. To enable this for all enums, define BETTER_ENUMS_CONSTEXPR_TO_STRING before including enum.h. Typically, you would pass an option to your compiler to do this.

You can also enable this feature for individual enums instead, by declaring them using the alternative SLOW_ENUM macro.

The feature is disabled because it increases compilation times by a factor of about 4. Compilation is still relatively fast — you need about a dozen slow enums to get the same penalty as including iostream — but it is a steep penalty nonetheless. I don't think most people need this feature most of the time, so it's too high a price to pay. If I improve compilation times to the point where compile-time name trimming can be the default, I will simply redefine SLOW_ENUM as BETTER_ENUM and deprecate it, so your code will still work.

Strict conversions

This disables implicit conversions to underlying integral types. At the moment, you can only enable this globally for all enums, by defining BETTER_ENUMS_STRICT_CONVERSION before including enum.h.

The reason Better Enums have implicit conversions to integral types in the first place is that in C++98, Better Enums have to be implicitly convertible to their member _enumerated types to be usable in switch statements. It is possible to avoid this in C++11 and convert to enum class types instead, but at the cost of breaking interface compatibility with C++98.

Here they are:

// Default variant
switch (channel) {
    case Channel::Red:   break;
    case Channel::Green: break;
    case Channel::Blue:  break;
}

// Strict variant
switch (channel) {
    case +Channel::Red:   break;
    case +Channel::Green: break;
    case +Channel::Blue:  break;
}

Injecting tokens

You can define BETTER_ENUMS_CLASS_ATTRIBUTE before declaring a Better Enum, to inject tokens into the class declaration. For example, in

#define BETTER_ENUMS_CLASS_ATTRIBUTE __attribute__(foo)
BETTER_ENUM(Channel, int, Red, Green, Blue)

The resulting enum declaration will begin with

class __attribute__(foo) Channel {