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

后端 未结 28 2320
逝去的感伤
逝去的感伤 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条回答
  •  清歌不尽
    2020-11-22 17:35

    #define ENUM_MAKE(TYPE, ...) \
            enum class TYPE {__VA_ARGS__};\
            struct Helper_ ## TYPE { \
                static const String& toName(TYPE type) {\
                    int index = static_cast(type);\
                    return splitStringVec()[index];}\
                static const TYPE toType(const String& name){\
                    static std::unordered_map 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(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;
    
       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;
        }
    

    example

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

    automatically ENUM_MAKE macro generate 'enum class' and helper class with 'enum reflection function'.

    In order to reduce mistakes, at once Everything is defined with only one ENUM_MAKE.

    The advantage of this code is automatically created for reflection and a close look at macro code ,easy-to-understand code. 'enum to string' , 'string to enum' performance both is algorithm O(1).

    Disadvantages is when first use , helper class for enum relection 's string vector and map is initialized. but If you want you'll also be pre-initialized. –

提交回复
热议问题