title: enum to std::string with Boost PP - Improving syntax
body: <p>I've started playing around with Boost's PP lib with an aim to write some small tool to help convert enumerations to strings.</p>
  
  <p>I've manged to get a solution where enums defined with a macro will also generate a complementary ToString function.</p>
  
  <p>I've played with various syntax styles, but I was unable to get one particular arrangement to work.</p>
  
  <p>This is what I have.</p>
  
  <pre><code>    namespace Examples
      {
          // This will define an enum class with an underlying uint8_t type
          ENUM_W_STR
          (fruit, uint8_t,
              (apple)
              (banana)
          );
  
          // Like above but with a different construction syntax
          ENUM_W_STR_2
          (fruit2, uint8_t,
              apple,
              banana
          );
  
          // This variant allows values to be assigned
          ENUM_W_STR_VAL
          (fruit3, uint8_t,
              (apple)      (1)
              (banana)     (2)
              (orange)     (3)
          );
      }
  </code></pre>
  
  <p>but, this is what I would like.</p>
  
  <pre><code>    ENUM_W_STR_2
      (fruit2, uint8_t,
          apple = 10,
          banana = 20
      );
  </code></pre>
  
  <p>I had issues with splitting the 'apple = 10' string
  when generating the switch statement in ToString. i.e., I could construct
  the enum but not the ToString function.</p>
  
  <p>Can this be achieved? If not with Boost PP, then some other means?</p>
  
  <p>Here is the source code (g++ 4.7.2, boost 1.50; clang 3.3  boost 1.57)</p>
  
  <pre><code>    #include &lt;boost/preprocessor.hpp&gt;
      #include &lt;iostream&gt;
  
      namespace EnumUtils{
  
      #define ENUMUTLS_STR_SWITCH_CASE(r, data, elem)\
          case data::elem : return BOOST_PP_STRINGIZE(elem);
  
      #define ENUMUTIL_EVEN(r, data,i, v)  BOOST_PP_IIF(BOOST_PP_MOD_D(r, i, 2),   ,v)
      #define ENUMUTIL_ODD( r, data,i, v)  BOOST_PP_IIF(BOOST_PP_MOD_D(r, i, 2),= v, )
      #define ENUMUTIL_ENUM_LINE(r, data, i, v)     ENUMUTIL_EVEN(r,data,i,v)    ENUMUTIL_ODD(r,data,i,v)    BOOST_PP_COMMA_IF(BOOST_PP_MOD_D(r,i,2))
  
      #define ENUMUTLS_STR_SWITCH_CASE_VAL_BASE(r, data, i, v)  BOOST_PP_IIF(BOOST_PP_MOD_D(r, i, 2),,ENUMUTLS_STR_SWITCH_CASE(r, data, v))
      #define ENUMUTLS_STR_SWITCH_CASE_VAL(     r, data, i, v)  ENUMUTLS_STR_SWITCH_CASE_VAL_BASE(r,data,i,v) 
  
  
      #define ENUM_W_STR(name, type, seq)\
          enum class name : type {\
              BOOST_PP_SEQ_ENUM(seq)\
          };\
          inline const char* ToString(name v)\
          {\
              switch (v)\
              {\
                  BOOST_PP_SEQ_FOR_EACH(\
                          ENUMUTLS_STR_SWITCH_CASE,\
                          name,\
                          seq)\
                  default: return "unknown " BOOST_PP_STRINGIZE(name);\
              }\
          }
  
      #define ENUM_W_STR_2(name, type, args...)\
          enum class name : type {\
              BOOST_PP_SEQ_ENUM(BOOST_PP_VARIADIC_TO_SEQ(args))\
          };\
          inline const char* ToString(name v)\
          {\
              switch (v)\
              {\
                  BOOST_PP_SEQ_FOR_EACH(\
                          ENUMUTLS_STR_SWITCH_CASE,\
                          name,\
                          BOOST_PP_VARIADIC_TO_SEQ(args))\
                  default: return "unknown " BOOST_PP_STRINGIZE(name);\
              }\
          }
  
  
      #define ENUM_W_STR_VAL(name, type, seq)\
          enum class name : type {\
              BOOST_PP_SEQ_FOR_EACH_I(\
                      ENUMUTIL_ENUM_LINE,\
                      name,\
                      seq)\
          };\
          inline const char* ToString(name v)\
          {\
              switch (v)\
              {\
                  BOOST_PP_SEQ_FOR_EACH_I(\
                          ENUMUTLS_STR_SWITCH_CASE_VAL,\
                          name,\
                          seq)\
                  default: return "unknown " BOOST_PP_STRINGIZE(name) ;\
              }\
          };
      }
  
      namespace Examples 
      {
        ENUM_W_STR 
        (fruit, uint8_t,
          (apple)
          (banana)
        );
  
        ENUM_W_STR_2
        (fruit2, uint8_t,
          apple,
          banana
        );
  
        ENUM_W_STR_VAL
        (fruit3, uint8_t,
          (apple)      (1)
          (banana)     (2)
          (orange)     (3)
       );
      }
  
      int main ()
      {
          std::cout &lt;&lt; Examples::ToString(Examples::fruit::apple)   &lt;&lt; std::endl;
          std::cout &lt;&lt; Examples::ToString(Examples::fruit::banana)  &lt;&lt; std::endl;
          std::cout &lt;&lt; Examples::ToString(Examples::fruit2::apple)  &lt;&lt; std::endl;
          std::cout &lt;&lt; Examples::ToString(Examples::fruit2::banana) &lt;&lt; std::endl;
          std::cout &lt;&lt; Examples::ToString(Examples::fruit3::apple)  &lt;&lt; std::endl;
          std::cout &lt;&lt; Examples::ToString(Examples::fruit3::banana) &lt;&lt; std::endl;
          return 0;
      }
  </code></pre>
  
  <p>output:</p>
  
  <pre><code>apple
  banana
  apple
  banana
  apple
  banana
  </code></pre>