Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>For the past week I've been looking for a way to do what you're asking for, and more. Here is what I came up with:</p> <pre><code>#define STD_ENUM_ENTRY_WITHOUT_VALUE__(ENUM, NAME) NAME, #define STD_ENUM_ENTRY_WITHOUT_VALUE_(ENUM, NAME) STD_ENUM_ENTRY_WITHOUT_VALUE__(ENUM, NAME) #define STD_ENUM_ENTRY_WITHOUT_VALUE(ENUM, SPLIT...) STD_ENUM_ENTRY_WITHOUT_VALUE_(ENUM, SPLIT) #define STD_ENUM_ENTRY_WITH_VALUE__(ENUM, NAME, VALUE) NAME = VALUE, #define STD_ENUM_ENTRY_WITH_VALUE_(ENUM, NAME, VALUE) STD_ENUM_ENTRY_WITH_VALUE__(ENUM, NAME, VALUE) #define STD_ENUM_ENTRY_WITH_VALUE(ENUM, SPLIT...) STD_ENUM_ENTRY_WITH_VALUE_(ENUM, SPLIT) #define FP_PP_ENUM_STD_ENTRY_1(ENUM, SPLIT...) STD_ENUM_ENTRY_WITHOUT_VALUE(ENUM, SPLIT) #define FP_PP_ENUM_STD_ENTRY_2(ENUM, SPLIT...) STD_ENUM_ENTRY_WITH_VALUE(ENUM, SPLIT) #define FP_PP_ENUM_STD_ENTRY__(N, ENUM, SPLIT...) FP_PP_ENUM_STD_ENTRY_##N(ENUM, SPLIT) #define FP_PP_ENUM_STD_ENTRY_(N, ENUM, VALUE) FP_PP_ENUM_STD_ENTRY__(N, ENUM, FP_PP_EXPAND VALUE) #define FP_PP_ENUM_STD_ENTRY(ENUM, VALUE) FP_PP_ENUM_STD_ENTRY_(FP_PP_NUM_ARGS VALUE, ENUM, VALUE) #define FP_PP_ENUM_EXT_ENTRY_WITHOUT_VALUE__(ENUM, NAME) ::fp::enum_entry&lt;ENUM&gt;(ENUM::NAME, #NAME), #define FP_PP_ENUM_EXT_ENTRY_WITHOUT_VALUE_(ENUM, NAME) FP_PP_ENUM_EXT_ENTRY_WITHOUT_VALUE__(ENUM, NAME) #define FP_PP_ENUM_EXT_ENTRY_WITHOUT_VALUE(ENUM, SPLIT...) FP_PP_ENUM_EXT_ENTRY_WITHOUT_VALUE_(ENUM, SPLIT) #define FP_PP_ENUM_EXT_ENTRY_WITH_VALUE__(ENUM, NAME, VALUE) ::fp::enum_entry&lt;ENUM&gt;(ENUM::NAME, #NAME), #define FP_PP_ENUM_EXT_ENTRY_WITH_VALUE_(ENUM, NAME, VALUE) FP_PP_ENUM_EXT_ENTRY_WITH_VALUE__(ENUM, NAME, VALUE) #define FP_PP_ENUM_EXT_ENTRY_WITH_VALUE(ENUM, SPLIT...) FP_PP_ENUM_EXT_ENTRY_WITH_VALUE_(ENUM, SPLIT) #define FP_PP_ENUM_EXT_ENTRY_1(ENUM, SPLIT...) FP_PP_ENUM_EXT_ENTRY_WITHOUT_VALUE(ENUM, SPLIT) #define FP_PP_ENUM_EXT_ENTRY_2(ENUM, SPLIT...) FP_PP_ENUM_EXT_ENTRY_WITH_VALUE(ENUM, SPLIT) #define FP_PP_ENUM_EXT_ENTRY__(N, ENUM, SPLIT...) FP_PP_ENUM_EXT_ENTRY_##N(ENUM, SPLIT) #define FP_PP_ENUM_EXT_ENTRY_(N, ENUM, VALUE) FP_PP_ENUM_EXT_ENTRY__(N, ENUM, FP_PP_EXPAND VALUE) #define FP_PP_ENUM_EXT_ENTRY(ENUM, VALUE) FP_PP_ENUM_EXT_ENTRY_(FP_PP_NUM_ARGS VALUE, ENUM, VALUE) #define DEFINE_EXT_ENUM(ENUM, ...) \ enum class ENUM { \ FP_PP_SEQ_FOR_EACH(FP_PP_ENUM_STD_ENTRY, ENUM, __VA_ARGS__) \ }; \ template&lt;typename&gt; \ struct enum_descriptor; \ \ template&lt;&gt; \ struct enum_descriptor&lt;ENUM&gt; { \ public: \ using enum_type = ENUM; \ using entry_type = ::fp::enum_entry&lt;enum_type&gt;; \ using this_type = enum_descriptor&lt;enum_type&gt;; \ using const_iterator = entry_type const *; \ using const_reverse_iterator = std::reverse_iterator&lt;const_iterator&gt;; \ using size_type = std::size_t; \ private: \ constexpr static std::size_t Size = FP_PP_NUM_ARGS(__VA_ARGS__); \ using container_type = std::array&lt;entry_type, Size&gt;; \ \ constexpr static container_type const _entries \ { \ { \ FP_PP_SEQ_FOR_EACH(FP_PP_ENUM_EXT_ENTRY, ENUM, __VA_ARGS__) \ } \ }; \ \ template&lt;std::size_t... Is &gt; \ constexpr static char const * name_of_impl(enum_type v, ::fp::indices&lt;Is...&gt;) { \ using std::get; \ return ::fp::enum_helper&lt;enum_type&gt;::get_name(v, get&lt;Is&gt;(_entries)...); \ } \ \ template&lt;std::size_t... Is &gt; \ constexpr static enum_type value_of_impl(char const * n, ::fp::indices&lt;Is...&gt;) { \ using std::get; \ return ::fp::enum_helper&lt;enum_type&gt;::get_value(n, get&lt;Is&gt;(_entries)...); \ } \ \ template&lt;typename V, std::size_t... Is &gt; \ static bool try_parse_impl(V val, enum_type &amp; res, ::fp::indices&lt;Is...&gt;) { \ using std::get; \ return (::fp::enum_helper&lt;enum_type&gt;::is_valid_entry(val, get&lt;Is&gt;(_entries)...)) ? \ ((res = static_cast&lt;enum_type&gt; (val)), true) \ : false; \ } \ \ template&lt;typename V, std::size_t... Is &gt; \ constexpr static enum_type parse_impl(V val, ::fp::indices&lt;Is...&gt;) { \ using std::get; \ return (::fp::enum_helper&lt;enum_type&gt;::parse(val, get&lt;Is&gt;(_entries)...)); \ } \ public: \ constexpr enum_descriptor() = default; \ enum_descriptor(enum_descriptor const &amp;) = delete; \ enum_descriptor(enum_descriptor &amp;&amp;) = delete; \ \ constexpr static char const * name() noexcept { \ return #ENUM; \ } \ \ constexpr static char const * name_of(enum_type value) { \ return name_of_impl(value, ::fp::build_indices&lt;Size&gt;()); \ } \ \ constexpr static enum_type value_of(char const * name) { \ return value_of_impl(name, ::fp::build_indices&lt;Size&gt;()); \ } \ \ constexpr static size_type size() noexcept { \ return Size; \ } \ \ constexpr static const_iterator begin() { \ using std::get; \ return const_iterator(&amp;get&lt;0&gt;(_entries)); \ } \ \ constexpr static const_iterator end() { \ using std::get; \ return const_iterator(&amp;get&lt;(Size - 1)&gt;(_entries) + 1); \ } \ \ template&lt;typename T, \ typename = typename std::enable_if&lt;std::is_integral&lt;T&gt;::value&gt;::type&gt; \ static bool try_parse(T value, enum_type &amp; res){ \ return try_parse_impl(value, res, ::fp::build_indices&lt;Size&gt;()); \ } \ \ template&lt;typename T, \ typename = typename std::enable_if&lt;std::is_integral&lt;T&gt;::value&gt;::type&gt; \ constexpr static enum_type parse(T value){ \ return parse_impl(value, ::fp::build_indices&lt;Size&gt;()); \ } \ }; \ template&lt;&gt; \ constexpr std::array&lt;::fp::enum_entry&lt;ENUM&gt;, FP_PP_NUM_ARGS(__VA_ARGS__)&gt; const enum_descriptor&lt;ENUM&gt;::_entries; </code></pre> <p>You can view the full code -including an example- on my <a href="https://github.com/wassup-/cxx-enum/" rel="nofollow">github</a>.</p> <p>Although this does what I expect it to do, this can not be (directly) used as a drop-in replacement for your existing enums.</p> <p>To save yourself a lot of coding, the enums you want to support should be defined like so:</p> <pre><code>DEFINE_EXT_ENUM(my_1st_enum, (fread, 3), (fwrite), (fflush, fread &lt;&lt; 2)); DEFINE_EXT_ENUM(my_2nd_enum, (fopen), (fclose, 1)); </code></pre> <p>One last thing: do not try to compile this on GCC with the -Werr flag, because compilation will error out (I understand why, but I do not currently know how to solve it).</p> <p>EDIT:</p> <p>Based on your example, this is how you would do it using my DEFINE_EXT_ENUM:</p> <pre><code>#include "enum_pp_def.hpp" #include &lt;cassert&gt; #include &lt;iostream&gt; DEFINE_EXT_ENUM(turn, (right,1), (left,2)); DEFINE_EXT_ENUM(hand, (right,1), (left,2)); using turn_descr = enum_descriptor&lt;turn&gt;; using hand_descr = enum_descriptor&lt;hand&gt;; /* 2 */ constexpr char const * foo(turn t) { return (turn_descr::is_valid((int)t)) ? (turn::right == t) ? "right turn" : "left turn" : throw t; } constexpr char const * foo(hand h) { return (hand_descr::is_valid((int)h)) ? (hand::right == h) ? "right hand" : "left hand" : throw h; } /* End 2 */ int main(int argc, char ** argv) { turn t1 = turn_descr::parse(1); // 3.a OK turn t2(turn::right); // 3b. OK hand h1(hand::left); // 3c. OK hand h2 = hand_descr::parse(2); // 3d. OK assert(t1 == turn::right); // 4. OK /* 8 */ switch(t1) { case turn::right: std::cout &lt;&lt; "right turn" &lt;&lt; std::endl; break; case turn::left: std::cout &lt;&lt; "left turn" &lt;&lt; std::endl; break; } /* End 8 */ std::cout &lt;&lt; foo(hand::left) &lt;&lt; std::endl; std::cout &lt;&lt; foo(turn::right) &lt;&lt; std::endl; constexpr turn t3 = turn_descr::parse(3) // throw at compile time turn t4 = turn_descr::parse(3); // throw at runtime } </code></pre>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload