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

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

    Adding even more simplicity of use to Jasper Bekkers' fantastic answer:

    Set up once:

    #define MAKE_ENUM(VAR) VAR,
    #define MAKE_STRINGS(VAR) #VAR,
    #define MAKE_ENUM_AND_STRINGS(source, enumName, enumStringName) \
        enum enumName { \
        source(MAKE_ENUM) \
        };\
    const char* const enumStringName[] = { \
        source(MAKE_STRINGS) \
        };
    

    Then, for usage:

    #define SOME_ENUM(DO) \
        DO(Foo) \
        DO(Bar) \
        DO(Baz)
    ...
    MAKE_ENUM_AND_STRINGS(SOME_ENUM, someEnum, someEnumNames)
    
    0 讨论(0)
  • 2020-11-22 11:02

    Note that your conversion function should ideally be returning a const char *.

    If you can afford to put your enums in their separate header files, you could perhaps do something like this with macros (oh, this will be ugly):

    #include "enum_def.h"
    #include "colour.h"
    #include "enum_conv.h"
    #include "colour.h"
    

    Where enum_def.h has:

    #undef ENUM_START
    #undef ENUM_ADD
    #undef ENUM_END
    #define ENUM_START(NAME) enum NAME {
    #define ENUM_ADD(NAME, VALUE) NAME = VALUE,
    #define ENUM_END };
    

    And enum_conv.h has:

    #undef ENUM_START
    #undef ENUM_ADD
    #undef ENUM_END
    #define ENUM_START(NAME) const char *##NAME##_to_string(NAME val) { switch (val) {
    #define ENUM_ADD(NAME, VALUE) case NAME: return #NAME;
    #define ENUM_END default: return "Invalid value"; } }
    

    And finally, colour.h has:

    ENUM_START(colour)
    ENUM_ADD(red,   0xff0000)
    ENUM_ADD(green, 0x00ff00)
    ENUM_ADD(blue,  0x0000ff)
    ENUM_END
    

    And you can use the conversion function as:

    printf("%s", colour_to_string(colour::red));
    

    This is ugly, but it's the only way (at the preprocessor level) that lets you define your enum just in a single place in your code. Your code is therefore not prone to errors due to modifications to the enum. Your enum definition and the conversion function will always be in sync. However, I repeat, this is ugly :)

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

    I have an incredibly simple to use macro that does this in a completely DRY fashion. It involves variadic macros and some simple parsing magic. Here goes:

    #define AWESOME_MAKE_ENUM(name, ...) enum class name { __VA_ARGS__, __COUNT}; \
    inline std::ostream& operator<<(std::ostream& os, name value) { \
    std::string enumName = #name; \
    std::string str = #__VA_ARGS__; \
    int len = str.length(); \
    std::vector<std::string> strings; \
    std::ostringstream temp; \
    for(int i = 0; i < len; i ++) { \
    if(isspace(str[i])) continue; \
            else if(str[i] == ',') { \
            strings.push_back(temp.str()); \
            temp.str(std::string());\
            } \
            else temp<< str[i]; \
    } \
    strings.push_back(temp.str()); \
    os << enumName << "::" << strings[static_cast<int>(value)]; \
    return os;} 
    

    To use this in your code, simply do:

    AWESOME_MAKE_ENUM(Animal,
        DOG,
        CAT,
        HORSE
    );
    
    0 讨论(0)
  • 2020-11-22 11:03
    #define stringify( name ) # name
    
    enum MyEnum {
        ENUMVAL1
    };
    ...stuff...
    
    stringify(EnumName::ENUMVAL1);  // Returns MyEnum::ENUMVAL1
    

    Further discussion on this method

    Preprocessor directive tricks for newcomers

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

    Here is an attempt to get << and >> stream operators on enum automatically with an one line macro command only...

    Definitions:

    #include <string>
    #include <iostream>
    #include <stdexcept>
    #include <algorithm>
    #include <iterator>
    #include <sstream>
    #include <vector>
    
    #define MAKE_STRING(str, ...) #str, MAKE_STRING1_(__VA_ARGS__)
    #define MAKE_STRING1_(str, ...) #str, MAKE_STRING2_(__VA_ARGS__)
    #define MAKE_STRING2_(str, ...) #str, MAKE_STRING3_(__VA_ARGS__)
    #define MAKE_STRING3_(str, ...) #str, MAKE_STRING4_(__VA_ARGS__)
    #define MAKE_STRING4_(str, ...) #str, MAKE_STRING5_(__VA_ARGS__)
    #define MAKE_STRING5_(str, ...) #str, MAKE_STRING6_(__VA_ARGS__)
    #define MAKE_STRING6_(str, ...) #str, MAKE_STRING7_(__VA_ARGS__)
    #define MAKE_STRING7_(str, ...) #str, MAKE_STRING8_(__VA_ARGS__)
    #define MAKE_STRING8_(str, ...) #str, MAKE_STRING9_(__VA_ARGS__)
    #define MAKE_STRING9_(str, ...) #str, MAKE_STRING10_(__VA_ARGS__)
    #define MAKE_STRING10_(str) #str
    
    #define MAKE_ENUM(name, ...) MAKE_ENUM_(, name, __VA_ARGS__)
    #define MAKE_CLASS_ENUM(name, ...) MAKE_ENUM_(friend, name, __VA_ARGS__)
    
    #define MAKE_ENUM_(attribute, name, ...) name { __VA_ARGS__ }; \
        attribute std::istream& operator>>(std::istream& is, name& e) { \
            const char* name##Str[] = { MAKE_STRING(__VA_ARGS__) }; \
            std::string str; \
            std::istream& r = is >> str; \
            const size_t len = sizeof(name##Str)/sizeof(name##Str[0]); \
            const std::vector<std::string> enumStr(name##Str, name##Str + len); \
            const std::vector<std::string>::const_iterator it = std::find(enumStr.begin(), enumStr.end(), str); \
            if (it != enumStr.end())\
                e = name(it - enumStr.begin()); \
            else \
                throw std::runtime_error("Value \"" + str + "\" is not part of enum "#name); \
            return r; \
        }; \
        attribute std::ostream& operator<<(std::ostream& os, const name& e) { \
            const char* name##Str[] = { MAKE_STRING(__VA_ARGS__) }; \
            return (os << name##Str[e]); \
        }
    

    Usage:

    // Declare global enum
    enum MAKE_ENUM(Test3, Item13, Item23, Item33, Itdsdgem43);
    
    class Essai {
    public:
        // Declare enum inside class
        enum MAKE_CLASS_ENUM(Test, Item1, Item2, Item3, Itdsdgem4);
    
    };
    
    int main() {
        std::cout << Essai::Item1 << std::endl;
    
        Essai::Test ffffd = Essai::Item1;
        std::cout << ffffd << std::endl;
    
        std::istringstream strm("Item2");
        strm >> ffffd;
    
        std::cout << (int) ffffd << std::endl;
        std::cout << ffffd << std::endl;
    }
    

    Not sure about the limitations of this scheme though... comments are welcome!

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

    Here is a CLI program I wrote to easily convert enums to strings. Its easy to use, and takes about 5 seconds to get it done (including the time to cd to the directory containing the program, then run it, passing to it the file containing the enum).

    Download here: http://www.mediafire.com/?nttignoozzz

    Discussion topic on it here: http://cboard.cprogramming.com/projects-job-recruitment/127488-free-program-im-sharing-convertenumtostrings.html

    Run the program with the "--help" argument to get a description how to use it.

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