enum to string in modern C++11 / C++14 / C++17 and future C++20

后端 未结 28 2222
逝去的感伤
逝去的感伤 2020-11-22 16:57

Contrary to all other similar questions, this question is about using the new C++ features.

  • 2008 c Is there a simple way to convert C++ enum to string?
  • <
28条回答
  •  -上瘾入骨i
    2020-11-22 17:19

    (Analogue of https://stackoverflow.com/a/54967187/2338477, slightly modified).

    Here is my own solution with minimum define magic and support of individual enum assignments.

    Here is header file:

    #pragma once
    #include 
    #include 
    #include 
    
    template 
    class EnumReflect
    {
    public:
        static const char* getEnums() { return ""; }
    };
    
    //
    //  Just a container for each enumeration type.
    //
    template 
    class EnumReflectBase
    {
    public:
        static std::map enum2int;
        static std::map 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 " = "
            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 
    std::map EnumReflectBase::enum2int;
    
    template 
    std::map EnumReflectBase::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 
    std::string EnumToString(T t)
    {
        EnumReflect::EnsureEnumMapReady(EnumReflect::getEnums());
        auto& int2enum = EnumReflect::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 
    bool StringToEnum(const char* enumName, T& t)
    {
        EnumReflect::EnsureEnumMapReady(EnumReflect::getEnums());
        auto& enum2int = EnumReflect::enum2int;
        auto it = enum2int.find(enumName);
    
        if (it == enum2int.end())
            return false;
    
        t = (T) it->second;
        return true;
    }
    

    And here is example test application:

    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);
    

    Updated version of same header file will be kept here:

    https://github.com/tapika/cppscriptcore/blob/master/SolutionProjectModel/EnumReflect.h

提交回复
热议问题