A fellow engineer at work asked me today how to convert an enum to a string value. This is what I came up with:

MyEnumToString function has a static map of MyEnum to const char*. In the assert it checks that the MyEnum::SIZE is equal to the size of the map: so you don’t forget to update the map when you update MyEnum with a new entry 😉

For larger enums would unordered_map be a better choice for the mapping data structure in terms of performance? Probably.


UPDATE

Several people on here and reddit suggested that the use of std::map or even std::unordered_map is an overkill. I agree. Though it is a must for non continuous enums (ones that do not start at 0 and do not increment by 1). Below is an updated MyEnumToString function which offers much faster conversion. It uses std::array to hold the string values.

10 Replies to “enum to string”

    1. Sebastian,
      No I have not heard of it. Thank you for bringing it to my attention! I will update the blog with this new information.

      BTW, playing around with the X Marco code it looks like it does not work for strongly typed enums 🙁

  1. Hi, your example with std::map and thought about using std::unordered_map seems wrong to me. Why not use C-style array or std::array? Yours enum starts at zero and doesn’t have gaps in it. Marek.

      1. Seen your update, good. Why assert? static_assert is better choice here, both left and right part of the == are known at compile time, so no need for run time check.

        Also if this is library code I would add assert(e>=0 and e<SIZE); at the beginning, because clients of your library might misbehave. For example when deserializeng the enum from file or network protocol (casting from some kind of integer) and not checking valid range there. Yes they have bug, but the crash is in your code. Assert would tell them it's their fault, not yours.

  2. First, thank you for enabling comments.

    I miss information about how to use formatting in comments. WordPress now supports markdown, but I’ll assume you have not enabled that. So in a sense this comment is a test: does it work to use HTML formatting, or would markdown be the correct way, or what? And in particular, how to format code: using

    HTML

    , or

    markdown

    , or what?

    The final function using std::array needlessly has three C style casts. Needless casts are Evil™, and using the C style syntax is generally also Evil™, because with that syntax the cast can change meaning when the code is modified. So even if it can be technically appropriate in a given case, it’s bad as an adopted practice. Since I’m unsure of the formatting I’ll not attempt to post code examples, but merely note that (1) the cast in the type definition is completely unnecessary and can just be removed; (2) the cast in the static assert can avoid a warning but avoiding that warning is IMO better done by completely removing the static assert, which serves no purpose in the current code (it did serve a purpose in the original code); and (3) the cast to size_t of the argument to

    at

    is better expressed as a cast to the enum’s underlying type, here int (one might define a prefix operator + to do that).

    Regarding the use of

    at

    , as with the

    static_cast

    that appears to be a remnant from the earlier code, and serves no useful purpose here.

    For clarity (so that readers, or yourself at a later time, don’t have to wonder why), replace with ordinary indexing.

  3. Thank you for your great post. I am trying to figure out your static assert statement. I think it will not work if you add a new entry to class enum without adding entry in the string array

    The size of the array will still be equal to MyEnum::SIZE and this assert will still be skipped
    static_assert(kMap.size() == (size_t)MyEnum::SIZE);

    I tried to test it.

    If I add VALUE_5 to the enum class I can still compile the code. The size of the array is constant and it is equal to second template parameter. If SIZE in test_enum is increased the size of the array will also be increased

    1. Good catch Slav! Yes looks like the array<…, SIZE> get’s initialized with default values for const char*. I’m not sure how to catch that right now. Let me think about this… if I come up with something I’ll update the code.

Leave a Reply