Boost logo

Boost :

Subject: Re: [boost] Query for interest in library: reflective enum
From: Dominique Devienne (ddevienne_at_[hidden])
Date: 2018-01-19 08:27:51


On Wed, Jan 17, 2018 at 9:21 PM, Nir Friedman via Boost <
boost_at_[hidden]> wrote:

> 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.
>

I'm interested! I also have something similar, inspired from
http://goo.gl/WBLL6,
but less sophisticated (no constexpr nor explicit enum integral, nor like
yours enum class support).

> ...

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.

ditto

> It requires variadic macros, and can probably target C++11 (if it doesn't
> already).

Mine is fine with C++03. What needs C++11, beside optionally making it
constexpr?
For backward-compatibility with 3rd party SDKs, I need support for ancient
compilers.

> I probably need to
> "comma harden" the macros for bizarre stuff like WISE_ENUM(Foo, (BAR,
> my_func<3,4>())).
>

Not of problem with mine, since does not support explicit integral values
:).
I've several times missed that though, this I'd welcome replacing mine
with yours.

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.
>

I also needed "nested" declarations, so this limitation is too restrictive
IMHO.
Mine uses two macros, the one to declare the enum, nested or not, and
another
one outside any namespace to declare the trait specializations that the
template
free functions equivalent to your _wise::to_string _wise::from_string use.

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.
>

FWIW, here's my API, which shows the features I already depend on.
Notably instead of using an optional to convert to the enum from text,
the declaration can specify an "invalid" / "unknown" enum value to map
to, which when not specified throws instead of returning the enum value.

template <typename TEnum>
std::string enum_name_of() {
    BOOST_STATIC_ASSERT((boost::is_enum<TEnum>::value));
    return EnumTypeTraits<TEnum>::name();
}

template <typename TEnum>
std::vector<TEnum> enum_values_of() {
    BOOST_STATIC_ASSERT((boost::is_enum<TEnum>::value));
    return EnumTypeTraits<TEnum>::values();
}

template <typename TEnum>
std::string enum_string_of(TEnum value) {
    BOOST_STATIC_ASSERT((boost::is_enum<TEnum>::value));
    return EnumTypeTraits<TEnum>::toString(value);
}

template <typename TEnum>
TEnum enum_value_of(const std::string& value_string) {
    BOOST_STATIC_ASSERT((boost::is_enum<TEnum>::value));
    return EnumTypeTraits<TEnum>::fromString(value_string);
}

/*!
 * \throw std::runtime_error if \a value_string is invalid and TEnum has no
 * \em invalid enum value.
 *
 * \note \b Silently returns the \em invalid enum on invalid \a
value_string,
 * if TEnum has one. Throws otherwise.
 */
template <typename TEnum>
void set_enum_value_from(const std::string& value_string, TEnum& value) {
    BOOST_STATIC_ASSERT((boost::is_enum<TEnum>::value));
    value = enum_value_of<TEnum>(value_string);
}

template <typename TEnum>
bool enum_has_invalid_value() {
    BOOST_STATIC_ASSERT((boost::is_enum<TEnum>::value));
    return EnumTypeTraits<TEnum>::hasInvalid();
}

template <typename TEnum>
TEnum enum_invalid_value() {
    BOOST_STATIC_ASSERT((boost::is_enum<TEnum>::value));
    return EnumTypeTraits<TEnum>::invalid();
}

template <typename TEnum>
bool enum_is_valid_value(TEnum value) {
    BOOST_STATIC_ASSERT((boost::is_enum<TEnum>::value));
    return EnumTypeTraits<TEnum>::isValidCode(value);
}

> 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!
>

I definitely do! --DD


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