Thanks to Sebastian Mestre (who commented on my previous post) I learned something new today 🙂 The X macro makes the enum to string code much… well, perhaps not cleaner, but shorter 😉 It also solves the problem of having to update the code in 2 places: 1st in the enum itself, 2nd in the enum to string map.
Without further ado I present to you the X macro:

And the complete implementation goes something like this:

In this version we only have to update the MY_ENUM macro. The rest is taken care of by the preprocessor.


UPDATE

Here’s the same approach that works with strongly typed enums:


UPDATE 2

Here’s the same approach that works with strongly typed enums, custom enum values, and enum values outside of the defined ones:

9 Replies to “enum to string, take 2”

  1. We could call this technique ‘preprocessor polymorphism’. Or a preprocessor Functor. Woohoo! Category theory for the working preprocessor!

  2. I would follow the C++ Core Guideline “ES.30: Don’t use macros for program text manipulation”.
    Just implement the enum_to_string function with a switch and explicit cases. Plain and understandable for everybody. Modern compiler will warn when there is a missing case switch when using a enum class.
    Code with macro’s are difficult to debug, produce difficult compiler warning/error messages.

    IMHO: plain switch has also more flexibility (load string from resource based on user locale, for example) or different string for a certain value and maintenance gain is small.

    Note 1: MyEnumToString can be made constexpr + noexcept.
    Note 2: of course plain switch can be “upgraded” when c++20 makes reflection possible.

    1. One problem with that header is that it’s too much apparently impenetrable code to relate to when something goes wrong. And Visual C++ and g++ differ in their preprocessor semantics. Things can go wrong, just with some option or new version, whatever.

  3. Instead of a switch inside the function, expand it to a sequence of stringified values inside an array. Then your enum is a direct map to an array entry containing the string. Much faster than the switch. And gag wash to people who say not to use the preprocessor. It’s a tool. Use it. If people can’t figure out the code let them use php.
    This technique is entirely valid and supported in every c++ preprocessor I know of. You can actually use this to do much more complex things. Ive used it to declare on a single line a lot of information and then from that build out multiple enums, arrays and structures. It makes it much easier to isolate updates to common data to a single place rather than having it scattered throughout your code.

  4. One change I would make to the code would be the below. It provides feed back for an unknown value and will also remove the warning: control reaches end of non-void function.

    constexpr const char* MyEnumToString(MyEnum e) noexcept
    {
    #define X(name) case(MY_ENUM_NAME::name): return #name;
    switch(e)
    {
    MY_ENUM
    }
    #undef X
    return “UNKNOWN”;
    }

    This is a nice option except it doesn’t seem to allow a starting value. For example I have an enum list of errors but they are all negative values. So for this I need to start from the lowest negative value and let it increment up. Is there a way to do that?

    enum class MY_ENUM_NAME : int8_t
    {
    CONNECTION_LOST_TO_HOST = -32,
    SOMETHING_BROKE_HERE,

    SUCCESS, // This will be 0

Leave a Reply