1. 7
  1. 4

    I use this package basically everywhere now. We do some really fun things with it in CHERIoT RTOS. For example, we define an enum of permissions and use magic enum to create a 32-bit bitmask of the valid values, which meant that we had only tiny code changes when we added and removed permissions. We mostly use it in assertions, but it’s also wired into our debugging infrastructure so that any log message that logs an enum can pretty-print it. That uses a fair amount of memory for the strings, but we only enable it in debugging modes, where we expect to have more SRAM available than a real deployment.

    1. 2

      This is a good read, but reminds me somewhat of DiWHY.

      I’d be interested to quantify the impact of this on compile time. I’ll be sticking with macro enums!

        1. 2

          It definitely hurts compile times, but the kind of code where it’s useful is often already quite heavily templated, so it’s hard to isolate the cost of the templates that made using magic_enum desirable, the cost of magic_enum, and the cost of the templates that were subsequently enabled by using magic_enum.

        2. 1

          Meanwhile, D:

          import std.conv : to;
          enum E { A, B }
          assert(E.A.to!string == "A");
          assert("A".to!E == E.A);
          

          (Yes, you can easily do this in usercode too. See BitFlags.)

          1. 2

            This bit of magic_enum is quite useful, but it’s not the biggest win for me. The select construct gives you the enum value as a constexpr, so you can use it to dispatch to a template function. The same is true for the for-each, This is incredibly useful for writing generic code. For example, this example uses the magic_enum for-each construct to run each of the tests in sequence. To add a new test, you just implement the test and add the enum value, and at the same time get a pretty-printed message of the thing that’s running.

            I’m not sure how D works with respect to generics vs dynamic dispatch, but magic_enum is a nice tool in C++ for bridging the two worlds.

            1. 1

              Meanwhile, D:

              template Test(E e)
              {
                  ...
              }
              static foreach (member; EnumMembers!E)
              {
                  ... Test!member ...
              }