On Wed, Jan 17, 2018 at 9:21 PM, Nir Friedman via Boost < boost@lists.boost.org> 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