Boost logo

Boost :

Subject: [boost] Query for interest in library: reflective enum
From: Nir Friedman (quicknir_at_[hidden])
Date: 2018-01-17 20:21:13


Hello,

I recently needed a reflective enum for work (that is an enum where you can
programmatically convert to and from strings, know how many enumerators
there are, and iterate over all enumerators). I looked online but I didn't
find anything that met my requirements. I was surprised that there wasn't
one in Boost. So I'd like to see if there is interest; I wrote an
implementation that I think has several nice features.

The most polished existing smart enum implementation I could find was
http://aantron.github.io/better-enums/. However, the enum implemented there
is not a true enum; it uses a nested member of a class kind of approach. So
for example, the is_enum type trait will not recognize is as an enum. You
cannot use it as a non-type template parameter.

I strongly think that a good generic smart enum macro should generate the
exact "vanilla" enum (or enum class) declaration. My library's syntax looks
like this:

WISE_ENUM(Foo, BAR, (BAZ, 3))

This generates, among other things, exactly:

enum Foo { BAR, BAZ=3};

I intend this as an explicit guarantee of the library that the programmer
can count on. That way when Foo is used for things unrelating to
reflection, the developer can be confident that there will not be any
surprises. Beyond compatability with C++ facilities for enums, and
minimizing surprise, another advantage of this approach is that it's
guaranteed to be backwards compatible. An existing codebase with an
existing enum/enum class can switch to this smart enum with very high
confidence that existing code will continue to work as before.

The WISE_ENUM macro, beyond generating the vanilla enum, also generates a
switch-case function for to-string conversion (for maximal efficiency), and
finally it generates a constexpr function that returns a
std::array<std::pair<const char*, Foo>> listing all of the arrays and their
string descriptions. This constexpr function, which is found via ADL,
allows writing a sequence of (constexpr) variables and functions providing
the rest of the desired functionality. Usage looks like this:

std::cerr << "My enum's size is : " << wise_enum::size<Foo> // this is
constexpr template variable
auto x = wise_enum::from_string<Foo>("BAR").value(); // from_string returns
an optional
auto y = wise_enum::to_string(x); // y is string literal, no heap
allocation

My implementation (POC level) is here: https://github.com/quicknir/wise_enum.
I don't yet have separate macros to cover enum/enum class/explicit/implicit
backing type combinations. It's only about 100 lines of code, leaning
heavily on BOOST_PP to do the heavy lifting. It requires variadic macros,
and can probably target C++11 (if it doesn't already). I probably need to
"comma harden" the macros for bizarre stuff like WISE_ENUM(Foo, (BAR,
my_func<3,4>())).

It has the limitation that the macro cannot be used inside a class (this is
hard to workaround for reflective macros). It's also unclear how repeated
enumeration values would be handled (enum Foo { BAR = 1, BAZ = 1}). As it
stands this will cause a compilation failure in the generated switch case
of the to_string function. Can discuss more in subsequent emails.

One suggested feature is an is_contiguous trait. Another reasonable bit of
functionality might be an is_wise_enum trait. Version 2 of this library
could target enum sets.

Although it's not fancy, I think this nicely covers a piece of
functionality I often need, and it does so avoiding any downside compared
to using a simple enum (beyond having to use macros). Hope other people
will agree!

Cheers,

Nir


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk