Is there a simple way to convert C++ enum to string?

后端 未结 30 2248
我在风中等你
我在风中等你 2020-11-22 10:37

Suppose we have some named enums:

enum MyEnum {
      FOO,
      BAR = 0x50
};

What I googled for is a script (any language) that scans all

相关标签:
30条回答
  • 2020-11-22 11:04

    Not so long ago I made some trick to have enums properly displayed in QComboBox and to have definition of enum and string representations as one statement

    #pragma once
    #include <boost/unordered_map.hpp>
    
    namespace enumeration
    {
    
       struct enumerator_base : boost::noncopyable
       {
          typedef
             boost::unordered_map<int, std::wstring>
             kv_storage_t;
          typedef
             kv_storage_t::value_type
             kv_type;
          kv_storage_t const & kv() const
          {
             return storage_;
          }
    
          LPCWSTR name(int i) const
          {
             kv_storage_t::const_iterator it = storage_.find(i);
             if(it != storage_.end())
                return it->second.c_str();
             return L"empty";
          }
    
       protected:
          kv_storage_t storage_;
       };
    
       template<class T>
       struct enumerator;
    
       template<class D>
       struct enum_singleton : enumerator_base
       {
          static enumerator_base const & instance()
          {
             static D inst;
             return inst;
          }
       };
    }
    
    #define QENUM_ENTRY(K, V, N)  K, N storage_.insert(std::make_pair((int)K, V));
    
    #define QBEGIN_ENUM(NAME, C)   \
    enum NAME                     \
    {                             \
       C                          \
    }                             \
    };                            \
    }                             \
    
    #define QEND_ENUM(NAME) \
    };                     \
    namespace enumeration  \
    {                      \
    template<>             \
    struct enumerator<NAME>\
       : enum_singleton< enumerator<NAME> >\
    {                      \
       enumerator()        \
       {
    
    //usage
    /*
    QBEGIN_ENUM(test_t,
       QENUM_ENTRY(test_entry_1, L"number uno",
       QENUM_ENTRY(test_entry_2, L"number dos",
       QENUM_ENTRY(test_entry_3, L"number tres",
    QEND_ENUM(test_t)))))
    */
    

    Now you've got enumeration::enum_singleton<your_enum>::instance() able to convert enums to strings. If you replace kv_storage_t with boost::bimap, you will also be able to do backward conversion. Common base class for converter was introduced to store it in Qt object, because Qt objects couldn't be templates

    Previous appearance

    0 讨论(0)
  • 2020-11-22 11:06

    Interesting to see the number of ways. here's one i used a long time ago:

    in file myenummap.h:

    #include <map>
    #include <string>
    enum test{ one, two, three, five=5, six, seven };
    struct mymap : std::map<unsigned int, std::string>
    {
      mymap()
      {
        this->operator[]( one ) = "ONE";
        this->operator[]( two ) = "TWO";
        this->operator[]( three ) = "THREE";
        this->operator[]( five ) = "FIVE";
        this->operator[]( six ) = "SIX";
        this->operator[]( seven ) = "SEVEN";
      };
      ~mymap(){};
    };
    

    in main.cpp

    #include "myenummap.h"
    
    ...
    mymap nummap;
    std::cout<< nummap[ one ] << std::endl;
    

    Its not const, but its convenient.

    Here's another way that uses C++11 features. This is const, doesn't inherit an STL container and is a little tidier:

    #include <vector>
    #include <string>
    #include <algorithm>
    #include <iostream>
    
    //These stay together and must be modified together
    enum test{ one, two, three, five=5, six, seven };
    std::string enum_to_str(test const& e)
    {
        typedef std::pair<int,std::string> mapping;
        auto m = [](test const& e,std::string const& s){return mapping(static_cast<int>(e),s);}; 
        std::vector<mapping> const nummap = 
        { 
            m(one,"one"), 
            m(two,"two"), 
            m(three,"three"),
            m(five,"five"),
            m(six,"six"),
            m(seven,"seven"),
        };
        for(auto i  : nummap)
        {
            if(i.first==static_cast<int>(e))
            {
                return i.second;
            }
        }
        return "";
    }
    
    int main()
    {
    //  std::cout<< enum_to_str( 46 ) << std::endl; //compilation will fail
        std::cout<< "Invalid enum to string : [" << enum_to_str( test(46) ) << "]"<<std::endl; //returns an empty string
        std::cout<< "Enumval five to string : ["<< enum_to_str( five ) << "] "<< std::endl; //works
        return 0;
    }
    
    0 讨论(0)
  • 2020-11-22 11:06
    #include <iostream>
    #include <map>
    #define IDMAP(x) (x,#x)
    
    std::map<int , std::string> enToStr;
    class mapEnumtoString
    {
    public:
        mapEnumtoString(){  }
        mapEnumtoString& operator()(int i,std::string str)
        {
            enToStr[i] = str;
            return *this;
        }
    public:
       std::string operator [] (int i)
        {
            return enToStr[i];
        }
    
    };
    mapEnumtoString k;
    mapEnumtoString& init()
    {
        return k;
    }
    
    int main()
    {
    
    init()
        IDMAP(1)
        IDMAP(2)
        IDMAP(3)
        IDMAP(4)
        IDMAP(5);
    std::cout<<enToStr[1];
    std::cout<<enToStr[2];
    std::cout<<enToStr[3];
    std::cout<<enToStr[4];
    std::cout<<enToStr[5];
    }
    
    0 讨论(0)
  • 2020-11-22 11:07

    As variant, use simple lib > http://codeproject.com/Articles/42035/Enum-to-String-and-Vice-Versa-in-C

    In the code

    #include <EnumString.h>
    
    enum FORM {
        F_NONE = 0,
        F_BOX,
        F_CUBE,
        F_SPHERE,
    };
    

    add lines

    Begin_Enum_String( FORM )
    {
        Enum_String( F_NONE );
        Enum_String( F_BOX );
        Enum_String( F_CUBE );
        Enum_String( F_SPHERE );
    }
    End_Enum_String;
    

    Work fine, if values in enum are not dublicate.

    Example usage

    enum FORM f = ...
    const std::string& str = EnumString< FORM >::From( f );
    

    and vice versa

    assert( EnumString< FORM >::To( f, str ) );
    
    0 讨论(0)
  • 2020-11-22 11:09

    @hydroo: Without the extra file:

    #define SOME_ENUM(DO) \
        DO(Foo) \
        DO(Bar) \
        DO(Baz)
    
    #define MAKE_ENUM(VAR) VAR,
    enum MetaSyntacticVariable{
        SOME_ENUM(MAKE_ENUM)
    };
    
    #define MAKE_STRINGS(VAR) #VAR,
    const char* const MetaSyntacticVariableNames[] = {
        SOME_ENUM(MAKE_STRINGS)
    };
    
    0 讨论(0)
  • 2020-11-22 11:09

    I do this with separate side-by-side enum wrapper classes which are generated with macros. There are several advantages:

    • Can generate them for enums I don't define (eg: OS platform header enums)
    • Can incorporate range checking into the wrapper class
    • Can do "smarter" formatting with bit field enums

    The downside, of course, is that I need to duplicate the enum values in the formatter classes, and I don't have any script to generate them. Other than that, though, it seems to work pretty well.

    Here's an example of an enum from my codebase, sans all the framework code which implements the macros and templates, but you can get the idea:

    enum EHelpLocation
    {
        HELP_LOCATION_UNKNOWN   = 0, 
        HELP_LOCAL_FILE         = 1, 
        HELP_HTML_ONLINE        = 2, 
    };
    class CEnumFormatter_EHelpLocation : public CEnumDefaultFormatter< EHelpLocation >
    {
    public:
        static inline CString FormatEnum( EHelpLocation eValue )
        {
            switch ( eValue )
            {
                ON_CASE_VALUE_RETURN_STRING_OF_VALUE( HELP_LOCATION_UNKNOWN );
                ON_CASE_VALUE_RETURN_STRING_OF_VALUE( HELP_LOCAL_FILE );
                ON_CASE_VALUE_RETURN_STRING_OF_VALUE( HELP_HTML_ONLINE );
            default:
                return FormatAsNumber( eValue );
            }
        }
    };
    DECLARE_RANGE_CHECK_CLASS( EHelpLocation, CRangeInfoSequential< HELP_HTML_ONLINE > );
    typedef ESmartEnum< EHelpLocation, HELP_LOCATION_UNKNOWN, CEnumFormatter_EHelpLocation, CRangeInfo_EHelpLocation > SEHelpLocation;
    

    The idea then is instead of using EHelpLocation, you use SEHelpLocation; everything works the same, but you get range checking and a 'Format()' method on the enum variable itself. If you need to format a stand-alone value, you can use CEnumFormatter_EHelpLocation::FormatEnum(...).

    Hope this is helpful. I realize this also doesn't address the original question about a script to actually generate the other class, but I hope the structure helps someone trying to solve the same problem, or write such a script.

    0 讨论(0)
提交回复
热议问题