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

后端 未结 30 2251
我在风中等你
我在风中等你 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 10:53

    What I tend to do is create a C array with the names in the same order and position as the enum values.

    eg.

    enum colours { red, green, blue };
    const char *colour_names[] = { "red", "green", "blue" };
    

    then you can use the array in places where you want a human-readable value, eg

    colours mycolour = red;
    cout << "the colour is" << colour_names[mycolour];
    

    You could experiment a little with the stringizing operator (see # in your preprocessor reference) that will do what you want, in some circumstances- eg:

    #define printword(XX) cout << #XX;
    printword(red);
    

    will print "red" to stdout. Unfortunately it won't work for a variable (as you'll get the variable name printed out)

    0 讨论(0)
  • 2020-11-22 10:55

    Here a one-file solution (based on elegant answer by @Marcin:

    #include <iostream>
    
    #define ENUM_TXT \
    X(Red) \
    X(Green) \
    X(Blue) \
    X(Cyan) \
    X(Yellow) \
    X(Magenta) \
    
    enum Colours {
    #   define X(a) a,
    ENUM_TXT
    #   undef X
        ColoursCount
    };
    
    char const* const colours_str[] = {
    #   define X(a) #a,
    ENUM_TXT
    #   undef X
        0
    };
    
    std::ostream& operator<<(std::ostream& os, enum Colours c)
    {
        if (c >= ColoursCount || c < 0) return os << "???";
        return os << colours_str[c] << std::endl;
    }
    
    int main()
    {
        std::cout << Red << Blue << Green << Cyan << Yellow << Magenta << std::endl;
    }
    
    0 讨论(0)
  • 2020-11-22 10:57

    It's unreleased software but it seems BOOST_ENUM from Frank Laub could fit the bill. The part I like about it is that you can define an enum within the scope of a class which most of the Macro based enums usually don't let you do. It is located in the Boost Vault at: http://www.boostpro.com/vault/index.php?action=downloadfile&filename=enum_rev4.6.zip&directory=& It hasn't seen any development since 2006 so I don't know how well it compiles with the new Boost releases. Look under libs/test for an example of usage.

    0 讨论(0)
  • 2020-11-22 10:59

    This is a modification to @user3360260 answer. It has the following new features

    • MyEnum fromString(const string&) support
    • compiles with VisualStudio 2012
    • the enum is an actual POD type (not just const declarations), so you can assign it to a variable.
    • added C++ "range" feature (in form of vector) to allow "foreach" iteration over enum

    Usage:

    SMART_ENUM(MyEnum, ONE=1, TWO, THREE, TEN=10, ELEVEN)
    MyEnum foo = MyEnum::TWO;
    cout << MyEnum::toString(foo);  // static method
    cout << foo.toString();         // member method
    cout << MyEnum::toString(MyEnum::TWO);
    cout << MyEnum::toString(10);
    MyEnum foo = myEnum::fromString("TWO");
    
    // C++11 iteration over all values
    for( auto x : MyEnum::allValues() )
    {
      cout << x.toString() << endl;
    }
    

    Here's the code

    #define SMART_ENUM(EnumName, ...)                                   \
    class EnumName                                                      \
    {                                                                   \
    public:                                                             \
        EnumName() : value(0) {}                                        \
        EnumName(int x) : value(x) {}                                   \
    public:                                                             \
        enum {__VA_ARGS__};                                             \
    private:                                                            \
        static void initMap(std::map<int, std::string>& tmp)                     \
        {                                                               \
            using namespace std;                                        \
                                                                        \
            int val = 0;                                                \
            string buf_1, buf_2, str = #__VA_ARGS__;                    \
            replace(str.begin(), str.end(), '=', ' ');                  \
            stringstream stream(str);                                   \
            vector<string> strings;                                     \
            while (getline(stream, buf_1, ','))                         \
                strings.push_back(buf_1);                               \
            for(vector<string>::iterator it = strings.begin();          \
                                                    it != strings.end(); \
                                                    ++it)                \
            {                                                           \
                buf_1.clear(); buf_2.clear();                           \
                stringstream localStream(*it);                          \
                localStream>> buf_1 >> buf_2;                           \
                if(buf_2.size() > 0)                                    \
                    val = atoi(buf_2.c_str());                          \
                tmp[val++] = buf_1;                                     \
            }                                                           \
        }                                                               \
        int value;                                                      \
    public:                                                             \
        operator int () const { return value; }                         \
        std::string toString(void) const {                              \
                return toString(value);                                 \
        }                                                               \
        static std::string toString(int aInt)                           \
        {                                                               \
            return nameMap()[aInt];                                     \
        }                                                               \
        static EnumName fromString(const std::string& s)                \
        {                                                               \
            auto it = find_if(nameMap().begin(), nameMap().end(), [s](const std::pair<int,std::string>& p) { \
                return p.second == s;                                   \
            });                                                         \
            if (it == nameMap().end()) {                                \
            /*value not found*/                                         \
                throw EnumName::Exception();                            \
            } else {                                                    \
                return EnumName(it->first);                             \
            }                                                           \
        }                                                               \
        class Exception : public std::exception {};                     \
        static std::map<int,std::string>& nameMap() {                   \
          static std::map<int,std::string> nameMap0;                    \
          if (nameMap0.size() ==0) initMap(nameMap0);                   \
          return nameMap0;                                              \
        }                                                               \
        static std::vector<EnumName> allValues() {                      \
          std::vector<EnumName> x{ __VA_ARGS__ };                       \
          return x;                                                     \
        }                                                               \
        bool operator<(const EnumName a) const { return (int)*this < (int)a; } \
    };         
    

    Note that the conversion toString is a fast has lookup, while the conversion fromString is a slow linear search. But strings are so expensive anyways(and the associated file IO), I didn't feel the need to optimize or use a bimap.

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

    A problem with answer 0 is that the enum binary values do not necessarily start at 0 and are not necessarily contiguous.

    When I need this, I usually:

    • pull the enum definition into my source
    • edit it to get just the names
    • do a macro to change the name to the case clause in the question, though typically on one line: case foo: return "foo";
    • add the switch, default and other syntax to make it legal
    0 讨论(0)
  • 2020-11-22 11:01

    This can be done in C++11

    #include <map>
    enum MyEnum { AA, BB, CC, DD };
    
    static std::map< MyEnum, const char * > info = {
       {AA, "This is an apple"},
       {BB, "This is a book"},
       {CC, "This is a coffee"},
       {DD, "This is a door"}
    };
    
    void main()
    {
        std::cout << info[AA] << endl
                  << info[BB] << endl
                  << info[CC] << endl
                  << info[DD] << endl;
    }
    
    0 讨论(0)
提交回复
热议问题