枚举到现代C+中的字符串+;11/C++;14/C++;17和未来的C++;20 与所有其他类似的问题相反,这个问题是关于使用新的C++特征。 2008年 2008年 2008年 2008年 2008年 2009年 2011年 2011年 2011年 2012年 2013年 在阅读了许多答案后,我还没有找到任何答案: 优雅的使用方式,还是新功能 或者是准备好用的东西 还有什么计划吗 例子

枚举到现代C+中的字符串+;11/C++;14/C++;17和未来的C++;20 与所有其他类似的问题相反,这个问题是关于使用新的C++特征。 2008年 2008年 2008年 2008年 2008年 2009年 2011年 2011年 2011年 2012年 2013年 在阅读了许多答案后,我还没有找到任何答案: 优雅的使用方式,还是新功能 或者是准备好用的东西 还有什么计划吗 例子,c,c++,string,enums,c++17,c++20,C,C++,String,Enums,C++17,C++20,一个例子往往比一个冗长的解释要好。 您可以在上编译并运行此代码段。 (也可提供) #包括 #包括 结构MyClass { 枚举类MyEnum:char{ AAA=-8, BBB='8', CCC=AAA+BBB }; }; //用更快的编译时生成的代码替换magic() //(您可以用std::string替换返回类型 //如果这对你来说更容易的话) 常量字符*魔法(MyClass::MyEnum e) { 常量std::映射myEnumString{ {MyClass::MyEnum::AAA

一个例子往往比一个冗长的解释要好。
您可以在上编译并运行此代码段。
(也可提供)

#包括
#包括
结构MyClass
{
枚举类MyEnum:char{
AAA=-8,
BBB='8',
CCC=AAA+BBB
};
};
//用更快的编译时生成的代码替换magic()
//(您可以用std::string替换返回类型
//如果这对你来说更容易的话)
常量字符*魔法(MyClass::MyEnum e)
{
常量std::映射myEnumString{
{MyClass::MyEnum::AAA,“MyClass::MyEnum::AAA”},
{MyClass::MyEnum::BBB,“MyClass::MyEnum::BBB”},
{MyClass::MyEnum::CCC,“MyClass::MyEnum::CCC”}
};
auto it=MyEnumStrings.find(e);
return it==MyEnumStrings.end()?“超出范围”:it->second;
}
int main()
{
std::cout对于C++17 C++20,您将对反思研究小组(SG7)的工作感兴趣。有一个平行系列的论文,涵盖措辞()和基本原理、设计和发展()(链接到每个系列中的最新论文)

从P0194r2(2016-10-15)起,语法将使用建议的
reflecpr
关键字:

meta::get_base_name_v<
  meta::get_element_m<
    meta::get_enumerators_m<reflexpr(MyEnum)>,
    0>
  >
meta::获取基本名称\u v<
meta::获取元素<
meta::获取枚举数,
0>
>
例如(改编自):

#包括
#包括
枚举MyEnum{AAA=1,BBB,CCC=99};
int main()
{
自动名称\u的\u MyEnum\u 0=
std::meta::get_base_name_v<
标准::元::获取元素<
标准::元::获取枚举数,
0>
>;
//打印“AAA”

std::cout一个简单的流式过载怎么样? 如果你不想做一些宏魔术,你仍然需要维护映射,但是我发现它比你原来的解决方案更干净

#include <cstdint>  // for std::uint_fast8_t
#include <array>
#include <string>
#include <iostream>

enum class MyEnum : std::uint_fast8_t {
   AAA,
   BBB,
   CCC,
};

std::ostream& operator<<(std::ostream& str, MyEnum type)
{
    switch(type)
    {
    case MyEnum::AAA: str << "AAA"; break;
    case MyEnum::BBB: str << "BBB"; break;
    case MyEnum::CCC: str << "CCC"; break;
    default: break;
    }
    return str;
}

int main()
{
   std::cout << MyEnum::AAA <<'\n';
}
\include//for std::uint\u fast8\t
#包括
#包括
#包括
枚举类MyEnum:std::uint\u fast8\t{
AAA,
BBB,
CCC,
};

std::ostream&operator根据OP的要求,这里是基于和的丑陋宏解决方案的精简版本

它允许枚举器元素的简单列表式语法以及特定元素的设置值,以便

XXX_ENUM(foo,(a,b,(c,42)));
扩展到

enum foo {
    a,
    b,
    c=42
};
这个宏已经存在了很多年了,我不能完全肯定它是最有效的方法,或者说它是一种一致的方法,但它一直在工作

完整的代码可以在和中看到

它巨大的丑陋是不可想象的;如果我知道怎么做的话,我会把它放在破坏者后面来保护你的眼睛,但马克唐不喜欢我

库(合并到单个头文件中) 输出
foo::a=foo::a
(int)foo::c=42
to_字符串(foo::b)=foo::b
xxx::enum_cast(“b”)=foo::b
并最终从未使用过它

我当前的步骤是启动Vim,复制空开关体中的枚举数,启动一个新宏,将第一个枚举数转换为case语句,将光标移动到下一行的开头,停止宏,并通过在其他枚举数上运行宏来生成剩余的case语句

vim宏比C++宏更有趣。

现实生活中的例子:

enum class EtherType : uint16_t
{
    ARP   = 0x0806,
    IPv4  = 0x0800,
    VLAN  = 0x8100,
    IPv6  = 0x86DD
};
int main () {

  VERB a = VERB::GET;
  VERB b = VERB::GET;
  VERB c = VERB::POST;
  VERB d = VERB::PUT;
  VERB e = VERB::DELETE;


  std::cout << a.toString() << std::endl;

  std::cout << a << std::endl;

  if ( a == VERB::GET ) {
    std::cout << "yes" << std::endl;
  }

  if ( a == b ) {
    std::cout << "yes" << std::endl;
  }

  if ( a != c ) {
    std::cout << "no" << std::endl;
  }

}
EnumToString(MyEnum, Red, Green, Blue);
我将创建以下内容:

std::ostream& operator<< (std::ostream& os, EtherType ethertype)
{
    switch (ethertype)
    {
        case EtherType::ARP : return os << "ARP" ;
        case EtherType::IPv4: return os << "IPv4";
        case EtherType::VLAN: return os << "VLAN";
        case EtherType::IPv6: return os << "IPv6";
        // omit default case to trigger compiler warning for missing cases
    };
    return os << static_cast<std::uint16_t>(ethertype);
}

std::ostream&operator我不知道您是否喜欢这个解决方案,我对这个解决方案不太满意,但它是一个C++14友好的方法,因为它使用模板变量并滥用模板专门化:

enum class MyEnum : std::uint_fast8_t {
   AAA,
   BBB,
   CCC,
};

template<MyEnum> const char MyEnumName[] = "Invalid MyEnum value";
template<> const char MyEnumName<MyEnum::AAA>[] = "AAA";
template<> const char MyEnumName<MyEnum::BBB>[] = "BBB";
template<> const char MyEnumName<MyEnum::CCC>[] = "CCC";

int main()
{
    // Prints "AAA"
    std::cout << MyEnumName<MyEnum::AAA> << '\n';
    // Prints "Invalid MyEnum value"
    std::cout << MyEnumName<static_cast<MyEnum>(0x12345678)> << '\n';
    // Well... in fact it prints "Invalid MyEnum value" for any value
    // different of MyEnum::AAA, MyEnum::BBB or MyEnum::CCC.

    return 0;
}
我们正在为每个
MyEnum
条目指定名称,可以在运行时使用:

std::cout << enum_values<MyEnum>[MyEnum::AAA] << '\n';
std::cout EDIT:查看下面的更新版本
如上所述,这是这件事的最终解决方案,但我们必须等待一年多才能看到它的出现

同时,如果您想要这样的功能,您需要求助于“简单”的模板和一些预处理器魔法

统计员 勘误表
#第0行
与GCC和clang上的
-pedantic
冲突

变通办法 从
第1行开始,然后从
第1行减去1
或者,不要使用
-pedantic

当我们在做这件事的时候,不惜一切代价避免VC++的使用,这一直是一个编译器的笑话

用法
#包括
命名空间级别
{
枚举类型(短);
#第0行
枚举(关闭);
枚举(严重);
枚举(警告);
#第10行
枚举(信息);
枚举(调试);
枚举(全部);
#行//恢复行编号
};
int main(int argc,字符**argv)
{
std::cout(图书馆的方法)

<>在当前的C++中有一种方法可以使字符串枚举:

initialize
(
    MyEnum::AAA, "AAA",
    MyEnum::BBB, "BBB",
    MyEnum::CCC, "CCC"
);
ENUM(Channel, char, Red = 1, Green, Blue)

// "Same as":
// enum class Channel : char { Red = 1, Green, Blue };
struct Channel {
    enum _enum : char { __VA_ARGS__ };
    constexpr static const Channel          _values[] = { __VA_ARGS__ };
    constexpr static const char * const     _names[] = { #__VA_ARGS__ };

    static const char* _to_string(Channel v) { /* easy */ }
    constexpr static Channel _from_string(const char *s) { /* easy */ }
};
用法:

Channel     c = Channel::_from_string("Green");  // Channel::Green (2)
c._to_string();                                  // string "Green"

for (Channel c : Channel::_values())
    std::cout << c << std::endl;

// And so on...
enum2str_generate(
  PATH          <path to place the files in>
  CLASS_NAME    <name of the class (also prefix for the files)>
  FUNC_NAME     <name of the (static) member function>
  NAMESPACE     <the class will be inside this namespace>
  INCLUDES      <LIST of files where the enums are defined>
  ENUMS         <LIST of enums to process>
  BLACKLIST     <LIST of constants to ignore>
  USE_CONSTEXPR <whether to use constexpr or not (default: off)>
  USE_C_STRINGS <whether to use c strings instead of std::string or not (default: off)>
)
问题是:

  • 我们将用“代码”> {Red=1,绿色,蓝色} /Clue作为值数组的初始化器。这是无效的C++,因为<代码>红色< /Cl>不是一个可赋值表达式。这是通过将每个常数都转换为具有赋值操作符的类型<代码> T >代码>来解决的,但是将放弃赋值:<代码> {(t)红色=1,(t)。绿色,(T)蓝色}
  • 类似地,我们最终将使用
    {“Red=1”、“Green”、“Blue”}
    作为名称数组的初始值设定项。我们需要删除
    “=1”
    。我不知道有什么好方法可以在编译时执行此操作,因此我们将把它推迟到运行时。因此,
    \u到\u字符串
    将不会是
    constepr
    ,但
    \u从\u字符串
    仍然可以是
    
    initialize
    (
        MyEnum::AAA, "AAA",
        MyEnum::BBB, "BBB",
        MyEnum::CCC, "CCC"
    );
    
    std::cout << enum_values<MyEnum>[MyEnum::AAA] << '\n';
    
    template<typename ENUM, class = typename std::enable_if<std::is_enum<ENUM>::value>::type>
    std::ostream &operator <<(std::ostream &o, const ENUM value)
    {
        static const std::string Unknown{std::string{typeid(ENUM).name()} + " unknown value"};
        auto found = enum_values<ENUM>.find(value);
    
        return o << (found == enum_values<ENUM>.end() ? Unknown : found->second);
    }
    
    std::cout << MyEnum::AAA << '\n';
    
    template<typename T>
    class Enum final
    {
        const char* m_name;
        const T m_value;
        static T m_counter;
    
    public:
        Enum(const char* str, T init = m_counter) : m_name(str), m_value(init) {m_counter = (init + 1);}
    
        const T value() const {return m_value;}
        const char* name() const {return m_name;}
    };
    
    template<typename T>
    T Enum<T>::m_counter = 0;
    
    #define ENUM_TYPE(x)      using Enum = Enum<x>;
    #define ENUM_DECL(x,...)  x(#x,##__VA_ARGS__)
    #define ENUM(...)         const Enum ENUM_DECL(__VA_ARGS__);
    
    #include <iostream>
    
    //the initialization order should be correct in all scenarios
    namespace Level
    {
        ENUM_TYPE(std::uint8)
        ENUM(OFF)
        ENUM(SEVERE)
        ENUM(WARNING)
        ENUM(INFO, 10)
        ENUM(DEBUG)
        ENUM(ALL)
    }
    
    namespace Example
    {
        ENUM_TYPE(long)
        ENUM(A)
        ENUM(B)
        ENUM(C, 20)
        ENUM(D)
        ENUM(E)
        ENUM(F)
    }
    
    int main(int argc, char** argv)
    {
        Level::Enum lvl = Level::WARNING;
        Example::Enum ex = Example::C;
        std::cout << lvl.value() << std::endl; //2
        std::cout << ex.value() << std::endl; //20
    }
    
    #define ENUM_TYPE(x) using type = Enum<x>
    #define ENUM(x)      constexpr type x{__LINE__,#x}
    
    template<typename T>
    struct Enum final
    {
        const T value;
        const char* name;
    
        constexpr operator const T() const noexcept {return value;}
        constexpr const char* operator&() const noexcept {return name;}
    };
    
    #include <iostream>
    
    namespace Level
    {
        ENUM_TYPE(short);
        #line 0
        ENUM(OFF);
        ENUM(SEVERE);
        ENUM(WARNING);
        #line 10
        ENUM(INFO);
        ENUM(DEBUG);
        ENUM(ALL);
        #line <next line number> //restore the line numbering
    };
    
    int main(int argc, char** argv)
    {
        std::cout << Level::OFF << std::endl;   // 0
        std::cout << &Level::OFF << std::endl;  // OFF
    
        std::cout << Level::INFO << std::endl;  // 10
        std::cout << &Level::INFO << std::endl; // INFO
    
        switch(/* any integer or integer-convertible type */)
        {
        case Level::OFF:
            //...
            break;
    
        case Level::SEVERE:
            //...
            break;
    
        //...
        }
    
        return 0;
    }
    
    ENUM(Channel, char, Red = 1, Green, Blue)
    
    // "Same as":
    // enum class Channel : char { Red = 1, Green, Blue };
    
    Channel     c = Channel::_from_string("Green");  // Channel::Green (2)
    c._to_string();                                  // string "Green"
    
    for (Channel c : Channel::_values())
        std::cout << c << std::endl;
    
    // And so on...
    
    struct Channel {
        enum _enum : char { __VA_ARGS__ };
        constexpr static const Channel          _values[] = { __VA_ARGS__ };
        constexpr static const char * const     _names[] = { #__VA_ARGS__ };
    
        static const char* _to_string(Channel v) { /* easy */ }
        constexpr static Channel _from_string(const char *s) { /* easy */ }
    };
    
    #include <cstddef>      // For size_t.
    #include <cstring>      // For strcspn, strncpy.
    #include <stdexcept>    // For runtime_error.
    
    
    
    // A "typical" mapping macro. MAP(macro, a, b, c, ...) expands to
    // macro(a) macro(b) macro(c) ...
    // The helper macro COUNT(a, b, c, ...) expands to the number of
    // arguments, and IDENTITY(x) is needed to control the order of
    // expansion of __VA_ARGS__ on Visual C++ compilers.
    #define MAP(macro, ...) \
        IDENTITY( \
            APPLY(CHOOSE_MAP_START, COUNT(__VA_ARGS__)) \
                (macro, __VA_ARGS__))
    
    #define CHOOSE_MAP_START(count) MAP ## count
    
    #define APPLY(macro, ...) IDENTITY(macro(__VA_ARGS__))
    
    #define IDENTITY(x) x
    
    #define MAP1(m, x)      m(x)
    #define MAP2(m, x, ...) m(x) IDENTITY(MAP1(m, __VA_ARGS__))
    #define MAP3(m, x, ...) m(x) IDENTITY(MAP2(m, __VA_ARGS__))
    #define MAP4(m, x, ...) m(x) IDENTITY(MAP3(m, __VA_ARGS__))
    #define MAP5(m, x, ...) m(x) IDENTITY(MAP4(m, __VA_ARGS__))
    #define MAP6(m, x, ...) m(x) IDENTITY(MAP5(m, __VA_ARGS__))
    #define MAP7(m, x, ...) m(x) IDENTITY(MAP6(m, __VA_ARGS__))
    #define MAP8(m, x, ...) m(x) IDENTITY(MAP7(m, __VA_ARGS__))
    
    #define EVALUATE_COUNT(_1, _2, _3, _4, _5, _6, _7, _8, count, ...) \
        count
    
    #define COUNT(...) \
        IDENTITY(EVALUATE_COUNT(__VA_ARGS__, 8, 7, 6, 5, 4, 3, 2, 1))
    
    
    
    // The type "T" mentioned above that drops assignment operations.
    template <typename U>
    struct ignore_assign {
        constexpr explicit ignore_assign(U value) : _value(value) { }
        constexpr operator U() const { return _value; }
    
        constexpr const ignore_assign& operator =(int dummy) const
            { return *this; }
    
        U   _value;
    };
    
    
    
    // Prepends "(ignore_assign<_underlying>)" to each argument.
    #define IGNORE_ASSIGN_SINGLE(e) (ignore_assign<_underlying>)e,
    #define IGNORE_ASSIGN(...) \
        IDENTITY(MAP(IGNORE_ASSIGN_SINGLE, __VA_ARGS__))
    
    // Stringizes each argument.
    #define STRINGIZE_SINGLE(e) #e,
    #define STRINGIZE(...) IDENTITY(MAP(STRINGIZE_SINGLE, __VA_ARGS__))
    
    
    
    // Some helpers needed for _from_string.
    constexpr const char    terminators[] = " =\t\r\n";
    
    // The size of terminators includes the implicit '\0'.
    constexpr bool is_terminator(char c, size_t index = 0)
    {
        return
            index >= sizeof(terminators) ? false :
            c == terminators[index] ? true :
            is_terminator(c, index + 1);
    }
    
    constexpr bool matches_untrimmed(const char *untrimmed, const char *s,
                                     size_t index = 0)
    {
        return
            is_terminator(untrimmed[index]) ? s[index] == '\0' :
            s[index] != untrimmed[index] ? false :
            matches_untrimmed(untrimmed, s, index + 1);
    }
    
    
    
    // The macro proper.
    //
    // There are several "simplifications" in this implementation, for the
    // sake of brevity. First, we have only one viable option for declaring
    // constexpr arrays: at namespace scope. This probably should be done
    // two namespaces deep: one namespace that is likely to be unique for
    // our little enum "library", then inside it a namespace whose name is
    // based on the name of the enum to avoid collisions with other enums.
    // I am using only one level of nesting.
    //
    // Declaring constexpr arrays inside the struct is not viable because
    // they will need out-of-line definitions, which will result in
    // duplicate symbols when linking. This can be solved with weak
    // symbols, but that is compiler- and system-specific. It is not
    // possible to declare constexpr arrays as static variables in
    // constexpr functions due to the restrictions on such functions.
    //
    // Note that this prevents the use of this macro anywhere except at
    // namespace scope. Ironically, the C++98 version of this, which can
    // declare static arrays inside static member functions, is actually
    // more flexible in this regard. It is shown in the CodeProject
    // article.
    //
    // Second, for compilation performance reasons, it is best to separate
    // the macro into a "parametric" portion, and the portion that depends
    // on knowing __VA_ARGS__, and factor the former out into a template.
    //
    // Third, this code uses a default parameter in _from_string that may
    // be better not exposed in the public interface.
    
    #define ENUM(EnumName, Underlying, ...)                               \
    namespace data_ ## EnumName {                                         \
        using _underlying = Underlying;                                   \
        enum { __VA_ARGS__ };                                             \
                                                                          \
        constexpr const size_t           _size =                          \
            IDENTITY(COUNT(__VA_ARGS__));                                 \
                                                                          \
        constexpr const _underlying      _values[] =                      \
            { IDENTITY(IGNORE_ASSIGN(__VA_ARGS__)) };                     \
                                                                          \
        constexpr const char * const     _raw_names[] =                   \
            { IDENTITY(STRINGIZE(__VA_ARGS__)) };                         \
    }                                                                     \
                                                                          \
    struct EnumName {                                                     \
        using _underlying = Underlying;                                   \
        enum _enum : _underlying { __VA_ARGS__ };                         \
                                                                          \
        const char * _to_string() const                                   \
        {                                                                 \
            for (size_t index = 0; index < data_ ## EnumName::_size;      \
                 ++index) {                                               \
                                                                          \
                if (data_ ## EnumName::_values[index] == _value)          \
                    return _trimmed_names()[index];                       \
            }                                                             \
                                                                          \
            throw std::runtime_error("invalid value");                    \
        }                                                                 \
                                                                          \
        constexpr static EnumName _from_string(const char *s,             \
                                               size_t index = 0)          \
        {                                                                 \
            return                                                        \
                index >= data_ ## EnumName::_size ?                       \
                        throw std::runtime_error("invalid identifier") :  \
                matches_untrimmed(                                        \
                    data_ ## EnumName::_raw_names[index], s) ?            \
                        (EnumName)(_enum)data_ ## EnumName::_values[      \
                                                                index] :  \
                _from_string(s, index + 1);                               \
        }                                                                 \
                                                                          \
        EnumName() = delete;                                              \
        constexpr EnumName(_enum value) : _value(value) { }               \
        constexpr operator _enum() const { return (_enum)_value; }        \
                                                                          \
      private:                                                            \
        _underlying     _value;                                           \
                                                                          \
        static const char * const * _trimmed_names()                      \
        {                                                                 \
            static char     *the_names[data_ ## EnumName::_size];         \
            static bool     initialized = false;                          \
                                                                          \
            if (!initialized) {                                           \
                for (size_t index = 0; index < data_ ## EnumName::_size;  \
                     ++index) {                                           \
                                                                          \
                    size_t  length =                                      \
                        std::strcspn(data_ ## EnumName::_raw_names[index],\
                                     terminators);                        \
                                                                          \
                    the_names[index] = new char[length + 1];              \
                                                                          \
                    std::strncpy(the_names[index],                        \
                                 data_ ## EnumName::_raw_names[index],    \
                                 length);                                 \
                    the_names[index][length] = '\0';                      \
                }                                                         \
                                                                          \
                initialized = true;                                       \
            }                                                             \
                                                                          \
            return the_names;                                             \
        }                                                                 \
    };
    
    // The code above was a "header file". This is a program that uses it.
    #include <iostream>
    #include "the_file_above.h"
    
    ENUM(Channel, char, Red = 1, Green, Blue)
    
    constexpr Channel   channel = Channel::_from_string("Red");
    
    int main()
    {
        std::cout << channel._to_string() << std::endl;
    
        switch (channel) {
            case Channel::Red:   return 0;
            case Channel::Green: return 1;
            case Channel::Blue:  return 2;
        }
    }
    
    static_assert(sizeof(Channel) == sizeof(char), "");
    
    DEF_MSG(CODE_OK,   "OK!")
    DEF_MSG(CODE_FAIL, "Fail!")
    
    get_message(CODE_FAIL);  // will return "Fail!"
    gm(CODE_FAIL);           // works exactly the same as above
    
    MSG_OK:     OK
    MSG_BOTTOM: Message bottom
    
    MSG_CODE foo(void) {
        return MSG_OK; // or something else
    }
    
    MSG_CODE ret = foo();
    
    if (MSG_OK != ret) {
        printf("%s\n", gm(ret););
    }
    
    #define ENUM_MAKE(TYPE, ...) \
            enum class TYPE {__VA_ARGS__};\
            struct Helper_ ## TYPE { \
                static const String& toName(TYPE type) {\
                    int index = static_cast<int>(type);\
                    return splitStringVec()[index];}\
                static const TYPE toType(const String& name){\
                    static std::unordered_map<String,TYPE> typeNameMap;\
                    if( typeNameMap.empty() )\
                    {\
                        const StringVector& ssVec = splitStringVec();\
                        for (size_t i = 0; i < ssVec.size(); ++i)\
                            typeNameMap.insert(std::make_pair(ssVec[i], static_cast<TYPE>(i)));\
                    }\
                    return typeNameMap[name];}\
                static const StringVector& splitStringVec() {\
                    static StringVector typeNameVector;\
                    if(typeNameVector.empty()) \
                    {\
                        typeNameVector = StringUtil::split(#__VA_ARGS__, ",");\
                        for (auto& name : typeNameVector)\
                        {\
                            name.erase(std::remove(name.begin(), name.end(), ' '),name.end()); \
                            name = String(#TYPE) + "::" + name;\
                        }\
                    }\
                    return typeNameVector;\
                }\
            };
    
    
    using String = std::string;
    using StringVector = std::vector<String>;
    
       StringVector StringUtil::split( const String& str, const String& delims, unsigned int maxSplits, bool preserveDelims)
        {
            StringVector ret;
            // Pre-allocate some space for performance
            ret.reserve(maxSplits ? maxSplits+1 : 10);    // 10 is guessed capacity for most case
    
            unsigned int numSplits = 0;
    
            // Use STL methods 
            size_t start, pos;
            start = 0;
            do 
            {
                pos = str.find_first_of(delims, start);
                if (pos == start)
                {
                    // Do nothing
                    start = pos + 1;
                }
                else if (pos == String::npos || (maxSplits && numSplits == maxSplits))
                {
                    // Copy the rest of the string
                    ret.push_back( str.substr(start) );
                    break;
                }
                else
                {
                    // Copy up to delimiter
                    ret.push_back( str.substr(start, pos - start) );
    
                    if(preserveDelims)
                    {
                        // Sometimes there could be more than one delimiter in a row.
                        // Loop until we don't find any more delims
                        size_t delimStart = pos, delimPos;
                        delimPos = str.find_first_not_of(delims, delimStart);
                        if (delimPos == String::npos)
                        {
                            // Copy the rest of the string
                            ret.push_back( str.substr(delimStart) );
                        }
                        else
                        {
                            ret.push_back( str.substr(delimStart, delimPos - delimStart) );
                        }
                    }
    
                    start = pos + 1;
                }
                // parse up to next real data
                start = str.find_first_not_of(delims, start);
                ++numSplits;
    
            } while (pos != String::npos);
    
    
    
            return ret;
        }
    
    ENUM_MAKE(MY_TEST, MY_1, MY_2, MY_3)
    
    
        MY_TEST s1 = MY_TEST::MY_1;
        MY_TEST s2 = MY_TEST::MY_2;
        MY_TEST s3 = MY_TEST::MY_3;
    
        String z1 = Helper_MY_TEST::toName(s1);
        String z2 = Helper_MY_TEST::toName(s2);
        String z3 = Helper_MY_TEST::toName(s3);
    
        MY_TEST q1 = Helper_MY_TEST::toType(z1);
        MY_TEST q2 = Helper_MY_TEST::toType(z2);
        MY_TEST q3 = Helper_MY_TEST::toType(z3);
    
                #include <unordered_map>
    
                enum class Language
                { unknown, 
                    Chinese, 
                    English, 
                    French, 
                    German
                    // etc etc
                };
    
                class Enumerations
                {
                public:
                    static void fnInit(void);
    
                    static std::unordered_map <std::wstring, Language> m_Language;
                    static std::unordered_map <Language, std::wstring> m_invLanguage;
    
                private:
                    static void fnClear();
                    static void fnSetValues(void);
                    static void fnInvertValues(void);
    
                    static bool m_init_done;
                };
    
                std::unordered_map <std::wstring, Language> Enumerations::m_Language = std::unordered_map <std::wstring, Language>();
                std::unordered_map <Language, std::wstring> Enumerations::m_invLanguage = std::unordered_map <Language, std::wstring>();
    
                void Enumerations::fnInit()
                {
                    fnClear();
                    fnSetValues();
                    fnInvertValues();
                }
    
                void Enumerations::fnClear()
                {
                    m_Language.clear();
                    m_invLanguage.clear();
                }
    
                void Enumerations::fnSetValues(void)
                {   
                    m_Language[L"unknown"] = Language::unknown;
                    m_Language[L"Chinese"] = Language::Chinese;
                    m_Language[L"English"] = Language::English;
                    m_Language[L"French"] = Language::French;
                    m_Language[L"German"] = Language::German;
                    // and more etc etc
                }
    
                void Enumerations::fnInvertValues(void)
                {
                    for (auto it = m_Language.begin(); it != m_Language.end(); it++)
                    {
                        m_invLanguage[it->second] = it->first;
                    }
                }
    
                // usage -
                //Language aLanguage = Language::English;
                //wstring sLanguage = Enumerations::m_invLanguage[aLanguage];
    
                //wstring sLanguage = L"French" ;
                //Language aLanguage = Enumerations::m_Language[sLanguage];
    
    #include <boost/preprocessor/seq/transform.hpp>
    #include <boost/preprocessor/seq/enum.hpp>
    #include <boost/preprocessor/stringize.hpp>
    
    #include <string>
    #include <array>
    #include <iostream>
    
    #define STRINGIZE(s, data, elem) BOOST_PP_STRINGIZE(elem)
    
    // ENUM
    // ============================================================================
    #define ENUM(X, SEQ) \
    struct X {   \
        enum Enum {BOOST_PP_SEQ_ENUM(SEQ)}; \
        static const std::array<std::string,BOOST_PP_SEQ_SIZE(SEQ)> array_of_strings() { \
            return {{BOOST_PP_SEQ_ENUM(BOOST_PP_SEQ_TRANSFORM(STRINGIZE, 0, SEQ))}}; \
        } \
        static std::string to_string(Enum e) { \
            auto a = array_of_strings(); \
            return a[static_cast<size_t>(e)]; \
        } \
    }
    
    enum2str_generate(
      PATH          <path to place the files in>
      CLASS_NAME    <name of the class (also prefix for the files)>
      FUNC_NAME     <name of the (static) member function>
      NAMESPACE     <the class will be inside this namespace>
      INCLUDES      <LIST of files where the enums are defined>
      ENUMS         <LIST of enums to process>
      BLACKLIST     <LIST of constants to ignore>
      USE_CONSTEXPR <whether to use constexpr or not (default: off)>
      USE_C_STRINGS <whether to use c strings instead of std::string or not (default: off)>
    )
    
    enum AAA : char { A1, A2 };
    
    typedef enum {
       VAL1          = 0,
       VAL2          = 1,
       VAL3          = 2,
       VAL_FIRST     = VAL1,    // Ignored
       VAL_LAST      = VAL3,    // Ignored
       VAL_DUPLICATE = 1,       // Ignored
       VAL_STRANGE   = VAL2 + 1 // Must be blacklisted
    } BBB;
    
    include_directories( ${PROJECT_SOURCE_DIR}/includes ...)
    
    enum2str_generate(
       PATH       "${PROJECT_SOURCE_DIR}"
       CLASS_NAME "enum2Str"
       NAMESPACE  "abc"
       FUNC_NAME  "toStr"
       INCLUDES   "a.h" # WITHOUT directory
       ENUMS      "AAA" "BBB"
       BLACKLIST  "VAL_STRANGE")
    
    /*!
      * \file enum2Str.hpp
      * \warning This is an automatically generated file!
      */
    
    #ifndef ENUM2STR_HPP
    #define ENUM2STR_HPP
    
    #include <string>
    #include <a.h>
    
    namespace abc {
    
    class enum2Str {
     public:
       static std::string toStr( AAA _var ) noexcept;
       static std::string toStr( BBB _var ) noexcept;
    };
    
    }
    
    #endif // ENUM2STR_HPP
    
    /*!
      * \file enum2Str.cpp
      * \warning This is an automatically generated file!
      */
    
    #include "enum2Str.hpp"
    
    namespace abc {
    
    /*!
     * \brief Converts the enum AAA to a std::string
     * \param _var The enum value to convert
     * \returns _var converted to a std::string
     */
    std::string enum2Str::toStr( AAA _var ) noexcept {
       switch ( _var ) {
          case A1: return "A1";
          case A2: return "A2";
          default: return "<UNKNOWN>";
       }
    }
    
    /*!
     * \brief Converts the enum BBB to a std::string
     * \param _var The enum value to convert
     * \returns _var converted to a std::string
     */
    std::string enum2Str::toStr( BBB _var ) noexcept {
       switch ( _var ) {
          case VAL1: return "VAL1";
          case VAL2: return "VAL2";
          case VAL3: return "VAL3";
          default: return "<UNKNOWN>";
       }
    }
    }
    
    First = 5
    Second
    Third = 7
    Fourth
    Fifth=11
    
    #include <iosfwd>
    
    enum class Hallo
    {
        First = 5,
        Second = 6,
        Third = 7,
        Fourth = 8,
        Fifth = 11
    };
    
    std::ostream & operator << (std::ostream &, const Hallo&);
    
    #include <ostream>
    
    #include "Hallo.h"
    
    std::ostream & operator << (std::ostream &out, const Hallo&value)
    {
        switch(value)
        {
        case Hallo::First:
            out << "First";
            break;
        case Hallo::Second:
            out << "Second";
            break;
        case Hallo::Third:
            out << "Third";
            break;
        case Hallo::Fourth:
            out << "Fourth";
            break;
        case Hallo::Fifth:
            out << "Fifth";
            break;
        default:
            out << "<unknown>";
        }
    
        return out;
    }
    
    package cppgen;
    
    import java.io.BufferedReader;
    import java.io.File;
    import java.io.FileInputStream;
    import java.io.FileOutputStream;
    import java.io.InputStreamReader;
    import java.io.OutputStreamWriter;
    import java.io.PrintWriter;
    import java.nio.charset.Charset;
    import java.util.LinkedHashMap;
    import java.util.Map;
    import java.util.Map.Entry;
    import java.util.regex.Matcher;
    import java.util.regex.Pattern;
    
    public class EnumGenerator
    {
        static void fail(String message)
        {
            System.err.println(message);
            System.exit(1);
        }
    
        static void run(String[] args)
        throws Exception
        {
            Pattern pattern = Pattern.compile("\\s*(\\w+)\\s*(?:=\\s*(\\d+))?\\s*", Pattern.UNICODE_CHARACTER_CLASS);
            Charset charset = Charset.forName("UTF8");
            String tab = "    ";
    
            if (args.length != 3)
            {
                fail("Required arguments: <enum name> <input file> <output dir>");
            }
    
            String enumName = args[0];
    
            File inputFile = new File(args[1]);
    
            if (inputFile.isFile() == false)
            {
                fail("Not a file: [" + inputFile.getCanonicalPath() + "]");
            }
    
            File outputDir = new File(args[2]);
    
            if (outputDir.isDirectory() == false)
            {
                fail("Not a directory: [" + outputDir.getCanonicalPath() + "]");
            }
    
            File headerFile = new File(outputDir, enumName + ".h");
            File codeFile = new File(outputDir, enumName + ".cpp");
    
            for (File file : new File[] { headerFile, codeFile })
            {
                if (file.exists())
                {
                    fail("Will not overwrite file [" + file.getCanonicalPath() + "]");
                }
            }
    
            int nextValue = 0;
    
            Map<String, Integer> fields = new LinkedHashMap<>();
    
            try
            (
                BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(inputFile), charset));
            )
            {
                while (true)
                {
                    String line = reader.readLine();
    
                    if (line == null)
                    {
                        break;
                    }
    
                    if (line.trim().length() == 0)
                    {
                        continue;
                    }
    
                    Matcher matcher = pattern.matcher(line);
    
                    if (matcher.matches() == false)
                    {
                        fail("Syntax error: [" + line + "]");
                    }
    
                    String fieldName = matcher.group(1);
    
                    if (fields.containsKey(fieldName))
                    {
                        fail("Double fiend name: " + fieldName);
                    }
    
                    String valueString = matcher.group(2);
    
                    if (valueString != null)
                    {
                        int value = Integer.parseInt(valueString);
    
                        if (value < nextValue)
                        {
                            fail("Not a monotonous progression from " + nextValue + " to " + value + " for enum field " + fieldName);
                        }
    
                        nextValue = value;
                    }
    
                    fields.put(fieldName, nextValue);
    
                    ++nextValue;
                }
            }
    
            try
            (
                PrintWriter headerWriter = new PrintWriter(new OutputStreamWriter(new FileOutputStream(headerFile), charset));
                PrintWriter codeWriter = new PrintWriter(new OutputStreamWriter(new FileOutputStream(codeFile), charset));
            )
            {
                headerWriter.println();
                headerWriter.println("#include <iosfwd>");
                headerWriter.println();
                headerWriter.println("enum class " + enumName);
                headerWriter.println('{');
                boolean first = true;
                for (Entry<String, Integer> entry : fields.entrySet())
                {
                    if (first == false)
                    {
                        headerWriter.println(",");
                    }
    
                    headerWriter.print(tab + entry.getKey() + " = " + entry.getValue());
    
                    first = false;
                }
                if (first == false)
                {
                    headerWriter.println();
                }
                headerWriter.println("};");
                headerWriter.println();
                headerWriter.println("std::ostream & operator << (std::ostream &, const " + enumName + "&);");
                headerWriter.println();
    
                codeWriter.println();
                codeWriter.println("#include <ostream>");
                codeWriter.println();
                codeWriter.println("#include \"" + enumName + ".h\"");
                codeWriter.println();
                codeWriter.println("std::ostream & operator << (std::ostream &out, const " + enumName + "&value)");
                codeWriter.println('{');
                codeWriter.println(tab + "switch(value)");
                codeWriter.println(tab + '{');
                first = true;
                for (Entry<String, Integer> entry : fields.entrySet())
                {
                    codeWriter.println(tab + "case " + enumName + "::" + entry.getKey() + ':');
                    codeWriter.println(tab + tab + "out << \"" + entry.getKey() + "\";");
                    codeWriter.println(tab + tab + "break;");
    
                    first = false;
                }
                codeWriter.println(tab + "default:");
                codeWriter.println(tab + tab + "out << \"<unknown>\";");
                codeWriter.println(tab + '}');
                codeWriter.println();
                codeWriter.println(tab + "return out;");
                codeWriter.println('}');
                codeWriter.println();
            }
        }
    
        public static void main(String[] args)
        {
            try
            {
                run(args);
            }
            catch(Exception exc)
            {
                exc.printStackTrace();
                System.exit(1);
            }
        }
    }
    
    import re
    import collections
    import sys
    import io
    import os
    
    def fail(*args):
        print(*args)
        exit(1)
    
    pattern = re.compile(r'\s*(\w+)\s*(?:=\s*(\d+))?\s*')
    tab = "    "
    
    if len(sys.argv) != 4:
        n=0
        for arg in sys.argv:
            print("arg", n, ":", arg, " / ", sys.argv[n])
            n += 1
        fail("Required arguments: <enum name> <input file> <output dir>")
    
    enumName = sys.argv[1]
    
    inputFile = sys.argv[2]
    
    if not os.path.isfile(inputFile):
        fail("Not a file: [" + os.path.abspath(inputFile) + "]")
    
    outputDir = sys.argv[3]
    
    if not os.path.isdir(outputDir):
        fail("Not a directory: [" + os.path.abspath(outputDir) + "]")
    
    headerFile = os.path.join(outputDir, enumName + ".h")
    codeFile = os.path.join(outputDir, enumName + ".cpp")
    
    for file in [ headerFile, codeFile ]:
        if os.path.exists(file):
            fail("Will not overwrite file [" + os.path.abspath(file) + "]")
    
    nextValue = 0
    
    fields = collections.OrderedDict()
    
    for line in open(inputFile, 'r'):
        line = line.strip()
    
        if len(line) == 0:
            continue
    
        match = pattern.match(line)
    
        if match == None:
            fail("Syntax error: [" + line + "]")
    
        fieldName = match.group(1)
    
        if fieldName in fields:
            fail("Double field name: " + fieldName)
    
        valueString = match.group(2)
    
        if valueString != None:
            value = int(valueString)
    
            if value < nextValue:
                fail("Not a monotonous progression from " + nextValue + " to " + value + " for enum field " + fieldName)
    
            nextValue = value
    
        fields[fieldName] = nextValue
    
        nextValue += 1
    
    headerWriter = open(headerFile, 'w')
    codeWriter = open(codeFile, 'w')
    
    try:
        headerWriter.write("\n")
        headerWriter.write("#include <iosfwd>\n")
        headerWriter.write("\n")
        headerWriter.write("enum class " + enumName + "\n")
        headerWriter.write("{\n")
        first = True
        for fieldName, fieldValue in fields.items():
            if not first:
                headerWriter.write(",\n")
    
            headerWriter.write(tab + fieldName + " = " + str(fieldValue))
    
            first = False
        if not first:
            headerWriter.write("\n")
        headerWriter.write("};\n")
        headerWriter.write("\n")
        headerWriter.write("std::ostream & operator << (std::ostream &, const " + enumName + "&);\n")
        headerWriter.write("\n")
    
        codeWriter.write("\n")
        codeWriter.write("#include <ostream>\n")
        codeWriter.write("\n")
        codeWriter.write("#include \"" + enumName + ".h\"\n")
        codeWriter.write("\n")
        codeWriter.write("std::ostream & operator << (std::ostream &out, const " + enumName + "&value)\n")
        codeWriter.write("{\n")
        codeWriter.write(tab + "switch(value)\n")
        codeWriter.write(tab + "{\n")
        for fieldName in fields.keys():
            codeWriter.write(tab + "case " + enumName + "::" + fieldName + ":\n")
            codeWriter.write(tab + tab + "out << \"" + fieldName + "\";\n")
            codeWriter.write(tab + tab + "break;\n")
        codeWriter.write(tab + "default:\n")
        codeWriter.write(tab + tab + "out << \"<unknown>\";\n")
        codeWriter.write(tab + "}\n")
        codeWriter.write("\n")
        codeWriter.write(tab + "return out;\n")
        codeWriter.write("}\n")
        codeWriter.write("\n")
    finally:
        headerWriter.close()
        codeWriter.close()
    
    struct Color
    {
        enum Enum { RED, GREEN, BLUE };
        Enum e;
    
        Color() {}
        Color(Enum e) : e(e) {}
    
        Color operator=(Enum o) { e = o; return *this; }
        Color operator=(Color o) { e = o.e; return *this; }
        bool operator==(Enum o) { return e == o; }
        bool operator==(Color o) { return e == o.e; }
        operator Enum() const { return e; }
    
        std::string toString() const
        {
            switch (e)
            {
            case Color::RED:
                return "red";
            case Color::GREEN:
                return "green";
            case Color::BLUE:
                return "blue";
            default:
                return "unknown";
            }
        }
    };
    
    Color red;
    red = Color::RED;
    Color blue = Color::BLUE;
    
    cout << red.toString() << " " << Color::GREEN << " " << blue << endl;
    
    Color color;
    switch (color) ...
    
    int i = color;
    
    struct Color
    {
        enum class Enum { RED, GREEN, BLUE };
        static const Enum RED = Enum::RED, GREEN = Enum::GREEN, BLUE = Enum::BLUE;
    
        //same as previous...
    };
    
    class Color
    {
    public:
        enum class Enum { RED, GREEN, BLUE };
        static const Enum RED = Enum::RED, GREEN = Enum::GREEN, BLUE = Enum::BLUE;
    
        constexpr Color() : e(Enum::RED) {}
        constexpr Color(Enum e) : e(e) {}
    
        constexpr bool operator==(Enum o) const { return e == o; }
        constexpr bool operator==(Color o) const { return e == o.e; }
        constexpr operator Enum() const { return e; }
    
        Color& operator=(Enum o) { const_cast<Enum>(this->e) = o; return *this; }
        Color& operator=(Color o) { const_cast<Enum>(this->e) = o.e; return *this; }
    
        std::string toString() const
        {
            switch (e)
            {
            case Enum::RED:
                return "red";
            case Enum::GREEN:
                return "green";
            case Enum::BLUE:
                return "blue";
            default:
                return "unknown";
            }
        }
    private:
        const Enum e;
    };
    
    #include <cstring> // http://stackoverflow.com/q/24520781
    
    template<typename KeyValue, typename ... RestOfKeyValues>
    struct map {
      static constexpr typename KeyValue::key_t get(const char* val) noexcept {
        if constexpr (sizeof...(RestOfKeyValues)==0)  // C++17 if constexpr
          return KeyValue::key; // Returns last element
        else {
          static_assert(KeyValue::val != nullptr,
                      "Only last element may have null name");
          return strcmp(val, KeyValue::val()) 
                ? map<RestOfKeyValues...>::get(val) : KeyValue::key;
        }
      }
      static constexpr const char* get(typename KeyValue::key_t key) noexcept {
        if constexpr (sizeof...(RestOfKeyValues)==0)
          return (KeyValue::val != nullptr) && (key == KeyValue::key)
                ? KeyValue::val() : "";
        else
          return (key == KeyValue::key) 
                ? KeyValue::val() : map<RestOfKeyValues...>::get(key);
      }
    };
    
    template<typename Enum, typename ... KeyValues>
    class names {
      typedef map<KeyValues...> Map;
    public:
      static constexpr Enum get(const char* nam) noexcept {
        return Map::get(nam);
      }
      static constexpr const char* get(Enum key) noexcept {
        return Map::get(key);
      }
    };
    
    enum class fasion {
        fancy,
        classic,
        sporty,
        emo,
        __last__ = emo,
        __unknown__ = -1
    };
    
    #define NAME(s) static inline constexpr const char* s() noexcept {return #s;}
    namespace name {
        NAME(fancy)
        NAME(classic)
        NAME(sporty)
        NAME(emo)
    }
    
    template<auto K, const char* (*V)()>  // C++17 template<auto>
    struct _ {
        typedef decltype(K) key_t;
        typedef decltype(V) name_t;
        static constexpr key_t  key = K; // enum id value
        static constexpr name_t val = V; // enum id name
    };
    
    typedef names<fasion,
        _<fasion::fancy, name::fancy>,
        _<fasion::classic, name::classic>,
        _<fasion::sporty, name::sporty>,
        _<fasion::emo, name::emo>,
        _<fasion::__unknown__, nullptr>
    > fasion_names;
    
    int main ()
    {
      constexpr auto str = fasion_names::get(fasion::emo);
      constexpr auto fsn = fasion_names::get(str);
      return (int) fsn;
    }
    
    main:
            mov     eax, 3
            ret
    
    enum MyEnum
    {
      AAA = -8,
      BBB = '8',
      CCC = AAA + BBB
    };
    
    AAA = -8,
    BBB = '8',
    CCC = AAA + BBB
    
    // default definition
    #ifned ITEM(X,Y)
    #define ITEM(X,Y)
    #endif
    
    // Items list
    ITEM(AAA,-8)
    ITEM(BBB,'8')
    ITEM(CCC,AAA+BBB)
    
    // clean up
    #undef ITEM
    
    enum MyEnum
    {
      #define ITEM(X,Y) X=Y,
      #include "enum_definition_file"
    };
    
    std::string ToString(MyEnum value)
    {
      switch( value )
      {
        #define ITEM(X,Y) case X: return #X;
        #include "enum_definition_file"
      }
    
      return "";
    }
    
    MyEnum FromString(std::string const& value)
    {
      static std::map<std::string,MyEnum> converter
      {
        #define ITEM(X,Y) { #X, X },
        #include "enum_definition_file"
      };
    
      auto it = converter.find(value);
      if( it != converter.end() )
        return it->second;
      else
        throw std::runtime_error("Value is missing");
    }
    
    int main () {
    
      VERB a = VERB::GET;
      VERB b = VERB::GET;
      VERB c = VERB::POST;
      VERB d = VERB::PUT;
      VERB e = VERB::DELETE;
    
    
      std::cout << a.toString() << std::endl;
    
      std::cout << a << std::endl;
    
      if ( a == VERB::GET ) {
        std::cout << "yes" << std::endl;
      }
    
      if ( a == b ) {
        std::cout << "yes" << std::endl;
      }
    
      if ( a != c ) {
        std::cout << "no" << std::endl;
      }
    
    }
    
    // -----------------------------------------------------------
    // -----------------------------------------------------------
    class VERB {
    
    private:
    
      // private constants
      enum Verb {GET_=0, POST_, PUT_, DELETE_};
    
      // private string values
      static const std::string theStrings[];
    
      // private value
      const Verb value;
      const std::string text;
    
      // private constructor
      VERB (Verb v) :
      value(v), text (theStrings[v])
      {
        // std::cout << " constructor \n";
      }
    
    public:
    
      operator const char * ()  const { return text.c_str(); }
    
      operator const std::string ()  const { return text; }
    
      const std::string toString () const { return text; }
    
      bool operator == (const VERB & other) const { return (*this).value == other.value; }
    
      bool operator != (const VERB & other) const { return ! ( (*this) == other); }
    
      // ---
    
      static const VERB GET;
      static const VERB POST;
      static const VERB PUT;
      static const VERB DELETE;
    
    };
    
    const std::string VERB::theStrings[] = {"GET", "POST", "PUT", "DELETE"};
    
    const VERB VERB::GET = VERB ( VERB::Verb::GET_ );
    const VERB VERB::POST = VERB ( VERB::Verb::POST_ );
    const VERB VERB::PUT = VERB ( VERB::Verb::PUT_ );
    const VERB VERB::DELETE = VERB ( VERB::Verb::DELETE_ );
    // end of file
    
    EnumToString(MyEnum, Red, Green, Blue);
    
    #include <iostream>
    using namespace std;
    
    class static_string
    {
        const char* const p_;
        const std::size_t sz_;
    
    public:
        typedef const char* const_iterator;
    
        template <std::size_t N>
        constexpr static_string(const char(&a)[N]) noexcept
            : p_(a)
            , sz_(N - 1)
        {}
    
        constexpr static_string(const char* p, std::size_t N) noexcept
            : p_(p)
            , sz_(N)
        {}
    
        constexpr const char* data() const noexcept { return p_; }
        constexpr std::size_t size() const noexcept { return sz_; }
    
        constexpr const_iterator begin() const noexcept { return p_; }
        constexpr const_iterator end()   const noexcept { return p_ + sz_; }
    
        constexpr char operator[](std::size_t n) const
        {
            return n < sz_ ? p_[n] : throw std::out_of_range("static_string");
        }
    };
    
    inline std::ostream& operator<<(std::ostream& os, static_string const& s)
    {
        return os.write(s.data(), s.size());
    }
    
    /// \brief Get the name of a type
    template <class T>
    static_string typeName()
    {
    #ifdef __clang__
        static_string p = __PRETTY_FUNCTION__;
        return static_string(p.data() + 30, p.size() - 30 - 1);
    #elif defined(_MSC_VER)
        static_string p = __FUNCSIG__;
        return static_string(p.data() + 37, p.size() - 37 - 7);
    #endif
    
    }
    
    namespace details
    {
        template <class Enum>
        struct EnumWrapper
        {
            template < Enum enu >
            static static_string name()
            {
    #ifdef __clang__
                static_string p = __PRETTY_FUNCTION__;
                static_string enumType = typeName<Enum>();
                return static_string(p.data() + 73 + enumType.size(), p.size() - 73 - enumType.size() - 1);
    #elif defined(_MSC_VER)
                static_string p = __FUNCSIG__;
                static_string enumType = typeName<Enum>();
                return static_string(p.data() + 57 + enumType.size(), p.size() - 57 - enumType.size() - 7);
    #endif
            }
        };
    }
    
    /// \brief Get the name of an enum value
    template <typename Enum, Enum enu>
    static_string enumName()
    {
        return details::EnumWrapper<Enum>::template name<enu>();
    }
    
    enum class Color
    {
        Blue = 0,
        Yellow = 1
    };
    
    
    int main() 
    {
        std::cout << "_" << typeName<Color>() << "_"  << std::endl;
        std::cout << "_" << enumName<Color, Color::Blue>() << "_"  << std::endl;
        return 0;
    }
    
    ENUM(Channel, int, Red, Green = 1, Blue)
    std::out << "My name is " << Channel::Green;
    //prints My name is Green
    
    #include <boost/algorithm/string.hpp>   
    struct EnumSupportBase {
      static std::vector<std::string> split(const std::string s, char delim) {
        std::stringstream ss(s);
        std::string item;
        std::vector<std::string> tokens;
        while (std::getline(ss, item, delim)) {
            auto pos = item.find_first_of ('=');
            if (pos != std::string::npos)
                item.erase (pos);
            boost::trim (item);
            tokens.push_back(item);
        }
        return tokens;
      }
    };
    #define ENUM(EnumName, Underlying, ...) \
        enum class EnumName : Underlying { __VA_ARGS__, _count }; \
        struct EnumName ## Support : EnumSupportBase { \
            static inline std::vector<std::string> _token_names = split(#__VA_ARGS__, ','); \
            static constexpr const char* get_name(EnumName enum_value) { \
                int index = (int)enum_value; \
                if (index >= (int)EnumName::_count || index < 0) \
                   return "???"; \
                else \
                   return _token_names[index].c_str(); \
            } \
        }; \
        inline std::ostream& operator<<(std::ostream& os, const EnumName & es) { \
            return os << EnumName##Support::get_name(es); \
        } 
    
    DECLARE_ENUM_WITH_TYPE(TestEnumClass, int32_t, ZERO = 0x00, TWO = 0x02, ONE = 0x01, THREE = 0x03, FOUR);
    
    #include <algorithm>
    #include <iostream>
    #include <map>
    #include <sstream>
    #include <string>
    #include <vector>
    
    #define STRING_REMOVE_CHAR(str, ch) str.erase(std::remove(str.begin(), str.end(), ch), str.end())
    
    std::vector<std::string> splitString(std::string str, char sep = ',') {
        std::vector<std::string> vecString;
        std::string item;
    
        std::stringstream stringStream(str);
    
        while (std::getline(stringStream, item, sep))
        {
            vecString.push_back(item);
        }
    
        return vecString;
    }
    
    #define DECLARE_ENUM_WITH_TYPE(E, T, ...)                                                                     \
        enum class E : T                                                                                          \
        {                                                                                                         \
            __VA_ARGS__                                                                                           \
        };                                                                                                        \
        std::map<T, std::string> E##MapName(generateEnumMap<T>(#__VA_ARGS__));                                    \
        std::ostream &operator<<(std::ostream &os, E enumTmp)                                                     \
        {                                                                                                         \
            os << E##MapName[static_cast<T>(enumTmp)];                                                            \
            return os;                                                                                            \
        }                                                                                                         \
        size_t operator*(E enumTmp) { (void) enumTmp; return E##MapName.size(); }                                 \
        std::string operator~(E enumTmp) { return E##MapName[static_cast<T>(enumTmp)]; }                          \
        std::string operator+(std::string &&str, E enumTmp) { return str + E##MapName[static_cast<T>(enumTmp)]; } \
        std::string operator+(E enumTmp, std::string &&str) { return E##MapName[static_cast<T>(enumTmp)] + str; } \
        std::string &operator+=(std::string &str, E enumTmp)                                                      \
        {                                                                                                         \
            str += E##MapName[static_cast<T>(enumTmp)];                                                           \
            return str;                                                                                           \
        }                                                                                                         \
        E operator++(E &enumTmp)                                                                                  \
        {                                                                                                         \
            auto iter = E##MapName.find(static_cast<T>(enumTmp));                                                 \
            if (iter == E##MapName.end() || std::next(iter) == E##MapName.end())                                  \
                iter = E##MapName.begin();                                                                        \
            else                                                                                                  \
            {                                                                                                     \
                ++iter;                                                                                           \
            }                                                                                                     \
            enumTmp = static_cast<E>(iter->first);                                                                \
            return enumTmp;                                                                                       \
        }                                                                                                         \
        bool valid##E(T value) { return (E##MapName.find(value) != E##MapName.end()); }
    
    #define DECLARE_ENUM(E, ...) DECLARE_ENUM_WITH_TYPE(E, int32_t, __VA_ARGS__)
    template <typename T>
    std::map<T, std::string> generateEnumMap(std::string strMap)
    {
        STRING_REMOVE_CHAR(strMap, ' ');
        STRING_REMOVE_CHAR(strMap, '(');
    
        std::vector<std::string> enumTokens(splitString(strMap));
        std::map<T, std::string> retMap;
        T inxMap;
    
        inxMap = 0;
        for (auto iter = enumTokens.begin(); iter != enumTokens.end(); ++iter)
        {
            // Token: [EnumName | EnumName=EnumValue]
            std::string enumName;
            T enumValue;
            if (iter->find('=') == std::string::npos)
            {
                enumName = *iter;
            }
            else
            {
                std::vector<std::string> enumNameValue(splitString(*iter, '='));
                enumName = enumNameValue[0];
                //inxMap = static_cast<T>(enumNameValue[1]);
                if (std::is_unsigned<T>::value)
                {
                    inxMap = static_cast<T>(std::stoull(enumNameValue[1], 0, 0));
                }
                else
                {
                    inxMap = static_cast<T>(std::stoll(enumNameValue[1], 0, 0));
                }
            }
            retMap[inxMap++] = enumName;
        }
    
        return retMap;
    }
    
    DECLARE_ENUM_WITH_TYPE(TestEnumClass, int32_t, ZERO = 0x00, TWO = 0x02, ONE = 0x01, THREE = 0x03, FOUR);
    
    int main(void) {
        TestEnumClass first, second;
        first = TestEnumClass::FOUR;
        second = TestEnumClass::TWO;
    
        std::cout << first << "(" << static_cast<uint32_t>(first) << ")" << std::endl; // FOUR(4)
    
        std::string strOne;
        strOne = ~first;
        std::cout << strOne << std::endl; // FOUR
    
        std::string strTwo;
        strTwo = ("Enum-" + second) + (TestEnumClass::THREE + "-test");
        std::cout << strTwo << std::endl; // Enum-TWOTHREE-test
    
        std::string strThree("TestEnumClass: ");
        strThree += second;
        std::cout << strThree << std::endl; // TestEnumClass: TWO
        std::cout << "Enum count=" << *first << std::endl;
    }
    
    // MyEnum.h
    #include <EnumTraits.h>
    #ifndef ENUM_INCLUDE_MULTI
    #pragma once
    #end if
    
    enum MyEnum : int ETRAITS
    {
        EDECL(AAA) = -8,
        EDECL(BBB) = '8',
        EDECL(CCC) = AAA + BBB
    };
    
    // MyEnum.cpp
    #define ENUM_DEFINE MyEnum
    #define ENUM_INCLUDE <MyEnum.h>
    #include <EnumTraits.inl>
    
    for (MyEnum value : EnumTraits<MyEnum>::GetValues())
        std::cout << EnumTraits<MyEnum>::GetName(value) << std::endl;
    
    // EnumTraits.h
    #pragma once
    #include <string>
    #include <unordered_map>
    #include <vector>
    
    #define ETRAITS
    #define EDECL(x) x
    
    template <class ENUM>
    class EnumTraits
    {
    public:
        static const std::vector<ENUM>& GetValues()
        {
            return values;
        }
    
        static ENUM GetValue(const char* name)
        {
            auto match = valueMap.find(name);
            return (match == valueMap.end() ? ENUM() : match->second);
        }
    
        static const char* GetName(ENUM value)
        {
            auto match = nameMap.find(value);
            return (match == nameMap.end() ? nullptr : match->second);
        }
    
    public:
        EnumTraits() = delete;
    
        using vector_type = std::vector<ENUM>;
        using name_map_type = std::unordered_map<ENUM, const char*>;
        using value_map_type = std::unordered_map<std::string, ENUM>;
    
    private:
        static const vector_type values;
        static const name_map_type nameMap;
        static const value_map_type valueMap;
    };
    
    struct EnumInitGuard{ constexpr const EnumInitGuard& operator=(int) const { return *this; } };
    template <class T> constexpr T& operator<<=(T&& x, const EnumInitGuard&) { return x; }
    
    // EnumTraits.inl
    #define ENUM_INCLUDE_MULTI
    
    #include ENUM_INCLUDE
    #undef ETRAITS
    #undef EDECL
    
    using EnumType = ENUM_DEFINE;
    using TraitsType = EnumTraits<EnumType>;
    using VectorType = typename TraitsType::vector_type;
    using NameMapType = typename TraitsType::name_map_type;
    using ValueMapType = typename TraitsType::value_map_type;
    using NamePairType = typename NameMapType::value_type;
    using ValuePairType = typename ValueMapType::value_type;
    
    #define ETRAITS ; const VectorType TraitsType::values
    #define EDECL(x) EnumType::x <<= EnumInitGuard()
    #include ENUM_INCLUDE
    #undef ETRAITS
    #undef EDECL
    
    #define ETRAITS ; const NameMapType TraitsType::nameMap
    #define EDECL(x) NamePairType(EnumType::x, #x) <<= EnumInitGuard()
    #include ENUM_INCLUDE
    #undef ETRAITS
    #undef EDECL
    
    #define ETRAITS ; const ValueMapType TraitsType::valueMap
    #define EDECL(x) ValuePairType(#x, EnumType::x) <<= EnumInitGuard()
    #include ENUM_INCLUDE
    #undef ETRAITS
    #undef EDECL
    
    namespace ns { enum MyEnum : int; }
    enum ns::MyEnum : int ETRAITS
    {
        EDECL(AAA) = -8,
        EDECL(BBB) = '8',
        EDECL(CCC) = ns::MyEnum::AAA + ns::MyEnum::BBB
    }
    
    enum class myenum
    {
      one = 0,
      two,
      three,
    };
    
    deque<string> ssplit(const string &_src, boost::regex &_re)
    {
      boost::sregex_token_iterator it(_src.begin(), _src.end(), _re, -1);
      boost::sregex_token_iterator e;
      deque<string> tokens;
      while (it != e)
        tokens.push_back(*it++);
      return std::move(tokens);
    }
    
    int main()
    {
      regex re(",");
      deque<string> tokens = ssplit("one,two,three", re);
      for (auto &t : tokens) cout << t << endl;
        getchar();
      return 0;
    }
    
    enum class MyEnum
    {
        Zero = 0,
        One  = 1,
        Two  = 2
    };
    
    ponder::Enum::declare<MyEnum>()
        .value("Zero", MyEnum::Zero)
        .value("One",  MyEnum::One)
        .value("Two",  MyEnum::Two);
    
    ponder::EnumObject zero(MyEnum::Zero);
    
    zero.name(); // -> "Zero"
    
    enum class test1 { ONE, TWO = 13, SIX };
    
    std::string toString(const test1& e) { ... }
    
    int main() {
        test1 x;
        std::cout << toString(x) << "\n";
        std::cout << toString(test1::TWO) << "\n";
        std::cout << static_cast<std::underlying_type<test1>::type>(test1::TWO) << "\n";
        //std::cout << toString(123);// invalid
    }
    
    ONE
    TWO
    13
    
    // x_enum.h
    #include <string>
    #include <map>
    #include <type_traits>
    #define x_begin enum class x_name {
    #define x_val(X) X
    #define x_value(X,Y) X = Y
    #define x_end };
    x_enum_def
    #undef x_begin
    #undef x_val
    #undef x_value
    #undef x_end
    
    #define x_begin inline std::string toString(const x_name& e) { \
                    static std::map<x_name,std::string> names = { 
    #define x_val(X)      { x_name::X , #X }
    #define x_value(X,Y)  { x_name::X , #X }
    #define x_end }; return names[e]; }
    x_enum_def
    #undef x_begin
    #undef x_val
    #undef x_value
    #undef x_end
    #undef x_name
    #undef x_enum_def
    
    #define x_name test1
    #define x_enum_def x_begin x_val(ONE) , \
                               x_value(TWO,13) , \
                               x_val(SIX) \
                       x_end
    #include "x_enum.h"
    
    #pragma once
    #include <string>
    #include <map>
    #include <regex>
    
    template <class Enum>
    class EnumReflect
    {
    public:
        static const char* getEnums() { return ""; }
    };
    
    //
    //  Just a container for each enumeration type.
    //
    template <class Enum>
    class EnumReflectBase
    {
    public:
        static std::map<std::string, int> enum2int;
        static std::map<int, std::string> int2enum;
    
        static void EnsureEnumMapReady( const char* enumsInfo )
        {
            if (*enumsInfo == 0 || enum2int.size() != 0 )
                return;
    
            // Should be called once per each enumeration.
            std::string senumsInfo(enumsInfo);
            std::regex re("^([a-zA-Z_][a-zA-Z0-9_]+) *=? *([^,]*)(,|$) *");     // C++ identifier to optional " = <value>"
            std::smatch sm;
            int value = 0;
    
            for (; regex_search(senumsInfo, sm, re); senumsInfo = sm.suffix(), value++)
            {
                string enumName = sm[1].str();
                string enumValue = sm[2].str();
    
                if (enumValue.length() != 0)
                    value = atoi(enumValue.c_str());
    
                enum2int[enumName] = value;
                int2enum[value] = enumName;
            }
        }
    };
    
    template <class Enum>
    std::map<std::string, int> EnumReflectBase<Enum>::enum2int;
    
    template <class Enum>
    std::map<int, std::string> EnumReflectBase<Enum>::int2enum;
    
    
    #define DECLARE_ENUM(name, ...)                                         \
        enum name { __VA_ARGS__ };                                          \
        template <>                                                         \
        class EnumReflect<##name>: public EnumReflectBase<##name> {         \
        public:                                                             \
            static const char* getEnums() { return #__VA_ARGS__; }          \
        };
    
    
    
    
    /*
        Basic usage:
    
        Declare enumeration:
    
    DECLARE_ENUM( enumName,
    
        enumValue1,
        enumValue2,
        enumValue3 = 5,
    
        // comment
        enumValue4
    );
    
        Conversion logic:
    
        From enumeration to string:
    
            printf( EnumToString(enumValue3).c_str() );
    
        From string to enumeration:
    
           enumName value;
    
           if( !StringToEnum("enumValue4", value) )
                printf("Conversion failed...");
    */
    
    //
    //  Converts enumeration to string, if not found - empty string is returned.
    //
    template <class T>
    std::string EnumToString(T t)
    {
        EnumReflect<T>::EnsureEnumMapReady(EnumReflect<T>::getEnums());
        auto& int2enum = EnumReflect<T>::int2enum;
        auto it = int2enum.find(t);
    
        if (it == int2enum.end())
            return "";
    
        return it->second;
    }
    
    //
    //  Converts string to enumeration, if not found - false is returned.
    //
    template <class T>
    bool StringToEnum(const char* enumName, T& t)
    {
        EnumReflect<T>::EnsureEnumMapReady(EnumReflect<T>::getEnums());
        auto& enum2int = EnumReflect<T>::enum2int;
        auto it = enum2int.find(enumName);
    
        if (it == enum2int.end())
            return false;
    
        t = (T) it->second;
        return true;
    }
    
    DECLARE_ENUM(TestEnum,
        ValueOne,
        ValueTwo,
        ValueThree = 5,
        ValueFour = 7
    );
    
    DECLARE_ENUM(TestEnum2,
        ValueOne2 = -1,
        ValueTwo2,
        ValueThree2 = -4,
        ValueFour2
    );
    
    void main(void)
    {
        string sName1 = EnumToString(ValueOne);
        string sName2 = EnumToString(ValueTwo);
        string sName3 = EnumToString(ValueThree);
        string sName4 = EnumToString(ValueFour);
    
        TestEnum t1, t2, t3, t4, t5 = ValueOne;
        bool b1 = StringToEnum(sName1.c_str(), t1);
        bool b2 = StringToEnum(sName2.c_str(), t2);
        bool b3 = StringToEnum(sName3.c_str(), t3);
        bool b4 = StringToEnum(sName4.c_str(), t4);
        bool b5 = StringToEnum("Unknown", t5);
    
        string sName2_1 = EnumToString(ValueOne2);
        string sName2_2 = EnumToString(ValueTwo2);
        string sName2_3 = EnumToString(ValueThree2);
        string sName2_4 = EnumToString(ValueFour2);
    
        TestEnum2 t2_1, t2_2, t2_3, t2_4, t2_5 = ValueOne2;
        bool b2_1 = StringToEnum(sName2_1.c_str(), t2_1);
        bool b2_2 = StringToEnum(sName2_2.c_str(), t2_2);
        bool b2_3 = StringToEnum(sName2_3.c_str(), t2_3);
        bool b2_4 = StringToEnum(sName2_4.c_str(), t2_4);
        bool b2_5 = StringToEnum("Unknown", t2_5);
    
    namespace enums
    {
    
    template <typename T, T I, char ...Chars>
    struct enums : std::integral_constant<T, I>
    {
      static constexpr char const chars[sizeof...(Chars)]{Chars...};
    };
    
    template <typename T, T X, typename S, std::size_t ...I>
    constexpr auto make(std::index_sequence<I...>) noexcept
    {
      return enums<T, X, S().chars[I]...>();
    }
    
    #define ENUM(s, n) []() noexcept{\
      struct S { char const (&chars)[sizeof(s)]{s}; };\
      return enums::make<decltype(n), n, S>(\
        std::make_index_sequence<sizeof(s)>());}()
    
    #define ENUM_T(s, n)\
      static constexpr auto s ## _tmp{ENUM(#s, n)};\
      using s ## _enum_t = decltype(s ## _tmp)
    
    template <typename T, typename ...A, std::size_t N>
    inline auto map(char const (&s)[N]) noexcept
    {
      constexpr auto invalid(~T{});
    
      auto r{invalid};
    
      return
        (
          (
            invalid == r ?
              r = std::strncmp(A::chars, s, N) ? invalid : A{} :
              r
          ),
          ...
        );
    }
    
    }
    
    int main()
    {
      ENUM_T(echo, 0);
      ENUM_T(cat, 1);
      ENUM_T(ls, 2);
    
      std::cout << echo_enum_t{} << " " << echo_enum_t::chars << std::endl;
    
      std::cout << enums::map<int, echo_enum_t, cat_enum_t, ls_enum_t>("ls")) << std::endl;
    
      return 0;
    }
    
    #include <iostream>
    #include <stdexcept>
    #include <regex>
    
    typedef std::string String;
    using namespace std::literals::string_literals;
    
    class Strings
    {
    public:
        static String TrimStart(const std::string& data)
        {
            String s = data;
            s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](unsigned char ch) {
                return !std::isspace(ch);
            }));
            return s;
        }
    
        static String TrimEnd(const std::string& data)
        {
            String s = data;
            s.erase(std::find_if(s.rbegin(), s.rend(), [](unsigned char ch) {
                return !std::isspace(ch);
            }).base(),
                s.end());
            return s;
        }
    
        static String Trim(const std::string& data)
        {
            return TrimEnd(TrimStart(data));
        }
    
        static String Replace(const String& data, const String& toFind, const String& toReplace)
        {
            String result = data;
            size_t pos = 0;
            while ((pos = result.find(toFind, pos)) != String::npos)
            {
                result.replace(pos, toFind.length(), toReplace);
                pos += toReplace.length();
                pos = result.find(toFind, pos);
            }
            return result;
        }
    
    };
    
    static String Nameof(const String& name)
    {
        std::smatch groups;
        String str = Strings::Trim(name);
        if (std::regex_match(str, groups, std::regex(u8R"(^&?([_a-zA-Z]\w*(->|\.|::))*([_a-zA-Z]\w*)$)")))
        {
            if (groups.size() == 4)
            {
                return groups[3];
            }
        }
        throw std::invalid_argument(Strings::Replace(u8R"(nameof(#). Invalid identifier "#".)", u8"#", name));
    }
    
    #define nameof(name) Nameof(u8## #name ## s)
    #define cnameof(name) Nameof(u8## #name ## s).c_str()
    
    enum TokenType {
        COMMA,
        PERIOD,
        Q_MARK
    };
    
    struct MyClass
    {
        enum class MyEnum : char {
            AAA = -8,
            BBB = '8',
            CCC = AAA + BBB
        };
    };
    
    int main() {
        String greetings = u8"Hello"s;
        std::cout << nameof(COMMA) << std::endl;
        std::cout << nameof(TokenType::PERIOD) << std::endl;
        std::cout << nameof(TokenType::Q_MARK) << std::endl;
        std::cout << nameof(int) << std::endl;
        std::cout << nameof(std::string) << std::endl;
        std::cout << nameof(Strings) << std::endl;
        std::cout << nameof(String) << std::endl;
        std::cout << nameof(greetings) << std::endl;
        std::cout << nameof(&greetings) << std::endl;
        std::cout << nameof(greetings.c_str) << std::endl;
        std::cout << nameof(std::string::npos) << std::endl;
        std::cout << nameof(MyClass::MyEnum::AAA) << std::endl;
        std::cout << nameof(MyClass::MyEnum::BBB) << std::endl;
        std::cout << nameof(MyClass::MyEnum::CCC) << std::endl;
    
    
        std::cin.get();
        return 0;
    }
    
    COMMA
    PERIOD
    Q_MARK
    int
    string
    Strings
    String
    greetings
    greetings
    c_str
    npos
    AAA
    BBB
    CCC
    
    enum
    {
      AAA = "AAA"_h8,
      BB = "BB"_h8,
    };
       
    std::cout << h8::to_string(AAA) << std::endl;
    std::cout << h8::to_string(BB) << std::endl;