Class implementation of C++ Enums

2019-09-26 04:33发布

问题:

According to the answer of BitWhistler https://stackoverflow.com/a/31626513/365229 I've implemented a class for C++ enums. Hope this helps other people who looking for this thing.

some operators overloaded for convenience and now you can use enums in c++ as an Object of a class. It also supports following operators:

  • << ostream
  • >> istream
  • + string concat
  • == object and enum comparison
  • != object and enum comparison
  • = string and enum assignment

check the answer.

回答1:

#define ENUM_MEMBER(MEMBER)                         \
    , MEMBER

#define ENUM_FROM_STRING(MEMBER)                    \
    if(str == #MEMBER ) return MEMBER;

#define ENUM_TO_STRING(MEMBER)                      \
    case MEMBER: return #MEMBER;

#define CREATE_ENUM_1(NAME,MACRO,DEFAULT)                               \
    class NAME {                                                        \
    public:                                                             \
        enum E {                                                        \
            DEFAULT                                                     \
            MACRO(ENUM_MEMBER)                                          \
        };                                                              \
    protected:                                                          \
        E _value;                                                       \
    public:                                                             \
        NAME() { _value = DEFAULT; }                                    \
        NAME(const NAME& copy) { _value = copy._value; }                \
        NAME(const char ch[]) : NAME(string(ch)) {}                     \
        NAME(const string& s) { _value = fromString(s); }               \
        NAME(const E en)                                                \
        { if(!isValid(en)) _value = DEFAULT; else _value = en; }        \
                                                                        \
        NAME& operator=(const NAME& r)                                  \
        {                                                               \
            if(this != &r)                                              \
                _value = r._value;                                      \
            return *this;                                               \
        }                                                               \
                                                                        \
        NAME& operator=(const NAME::E& r)                               \
        {                                                               \
            _value = r;                                                 \
            return *this;                                               \
        }                                                               \
                                                                        \
        bool operator==(const NAME::E& r) const { return _value == r; }          \
        bool operator!=(const NAME::E& r) const { return _value != r; }          \
        bool operator==(const NAME& r) const { return _value == r._value; }      \
        bool operator!=(const NAME& r) const { return _value != r._value; }      \
        string operator+(const string& r) const { return toString() + r; }       \
        NAME::E value() const { return _value; }                                 \
                                                                                     \
        string toString() const { return name(_value); }                             \
        NAME::E fromString(const string& str)                                        \
            { _value = parse(str); return _value; }                                  \
                                                                                     \
        static vector<NAME> getVector()                                              \
        {                                                                            \
            static vector<NAME> vec = { DEFAULT MACRO(ENUM_MEMBER) };                \
            return vec;                                                              \
        }                                                                            \
                                                                                     \
        static E getDefault() { return E::DEFAULT; }                                 \
        static string name(const NAME::E e)                             \
        {                                                               \
            switch( e ) {                                               \
                MACRO(ENUM_TO_STRING)                                   \
                default: return #DEFAULT;                               \
            }                                                           \
        }                                                               \
                                                                        \
        static E parse(const string& str)                               \
        {                                                               \
            MACRO(ENUM_FROM_STRING)                                     \
            return E::DEFAULT;                                          \
        }                                                               \
                                                                        \
        static size_t count()                                           \
        {                                                               \
            static E all[] = { DEFAULT MACRO(ENUM_MEMBER) };            \
            return sizeof(all) / sizeof(E);                             \
        }                                                               \
                                                                        \
        static bool isValid(const string& str)                          \
        {                                                               \
            E e = parse(str);                                           \
            if(e == E::DEFAULT && str != #DEFAULT)                      \
                return false;                                           \
            return true;                                                \
        }                                                               \
                                                                        \
        static bool isValid(const int val)                              \
        {                                                               \
            string s = name((NAME::E)val);                              \
            if(s == #DEFAULT && val != E::DEFAULT)                      \
                return false;                                           \
            return true;                                                \
        }                                                               \
    };\
string operator+(const string& l, const NAME& en);  \
std::ostream& operator<<(std::ostream& s, const NAME& en); \
std::istream& operator>>(std::istream& s, NAME& en);

#define CREATE_ENUM_2(NAME,DEFAULT) \
    CREATE_ENUM_1(NAME,NAME##_Members,DEFAULT)

#define CREATE_ENUM(NAME,DEFAULT) \
    CREATE_ENUM_2(NAME,DEFAULT)

use this macro in source code to avoid link error:

#define CREATE_ENUM_CPP(NAME) \
string operator+(const string& l, const NAME& en) { return l + en.toString(); }  \
std::ostream& operator<<(std::ostream& s, const NAME& en) { s << en.toString(); return s;} \
std::istream& operator>>(std::istream& s, NAME& en) { string t; s >> t; en.fromString(t); return s;}

Usage

#define Animal_Members(ENUM) \
    ENUM(DOG) \
    ENUM(CAT) \
    ENUM(COW) \

CREATE_ENUM(Animal,None)
// in source code:
CREATE_ENUM_CPP(Animal)

TEST

cout << Animal::parse("CAT") << endl;
cout << Animal::parse("INVALID STRING") << endl;
cout << Animal::name(Animal::CAT) << endl;
auto vec = Animal::getVector();
for(auto it = vec.begin(); it != vec.end() ; ++it)
    cout << *it << endl;

Animal cat = "CAT", DOG = "DOG";
cout << "(cat == DOG): " << (cat == DOG) << endl;
Animal a = "CAT";
string string_concat = "VALUE: " + a;
cout << string_concat << endl;
cin >> a;
cout << "INPUT: " << a << endl;
cout << "defalut=" << Animal(Animal::getDefault()) << endl;

Animal d("DOG"); // string init
d = "COW"; // string assignment;
d = Animal::CAT; // enum assginment;
Animal e = d; //copy constructor
cout << "(e == d): " << (e == d) << endl; // compare