Easy way to use variables of enum types as string in C?

前端 未结 19 2312
太阳男子
太阳男子 2020-11-22 08:47

Here\'s what I am trying to do:

typedef enum { ONE, TWO, THREE } Numbers;

I am trying to write a function that would do a switch case sim

19条回答
  •  执念已碎
    2020-11-22 09:15

    I have created a simple templated class streamable_enum that uses stream operators << and >> and is based on the std::map:

    #ifndef STREAMABLE_ENUM_HPP
    #define STREAMABLE_ENUM_HPP
    
    #include 
    #include 
    #include 
    
    template 
    class streamable_enum
    {
    public:
        typedef typename std::map tostr_map_t;
        typedef typename std::map fromstr_map_t;
    
        streamable_enum()
        {}
    
        streamable_enum(E val) :
            Val_(val)
        {}
    
        operator E() {
            return Val_;
        }
    
        bool operator==(const streamable_enum& e) {
            return this->Val_ == e.Val_;
        }
    
        bool operator==(const E& e) {
            return this->Val_ == e;
        }
    
        static const tostr_map_t& to_string_map() {
            static tostr_map_t to_str_(get_enum_strings());
            return to_str_;
        }
    
        static const fromstr_map_t& from_string_map() {
            static fromstr_map_t from_str_(reverse_map(to_string_map()));
            return from_str_;
        }
    private:
        E Val_;
    
        static fromstr_map_t reverse_map(const tostr_map_t& eToS) {
            fromstr_map_t sToE;
            for (auto pr : eToS) {
                sToE.emplace(pr.second, pr.first);
            }
            return sToE;
        }
    };
    
    template 
    streamable_enum stream_enum(E e) {
        return streamable_enum(e);
    }
    
    template 
    typename streamable_enum::tostr_map_t get_enum_strings() {
        // \todo throw an appropriate exception or display compile error/warning
        return {};
    }
    
    template 
    std::ostream& operator<<(std::ostream& os, streamable_enum e) {
        auto& mp = streamable_enum::to_string_map();
        auto res = mp.find(e);
        if (res != mp.end()) {
            os << res->second;
        } else {
            os.setstate(std::ios_base::failbit);
        }
        return os;
    }
    
    template 
    std::istream& operator>>(std::istream& is, streamable_enum& e) {
        std::string str;
        is >> str;
        if (str.empty()) {
            is.setstate(std::ios_base::failbit);
        }
        auto& mp = streamable_enum::from_string_map();
        auto res = mp.find(str);
        if (res != mp.end()) {
            e = res->second;
        } else {
            is.setstate(std::ios_base::failbit);
        }
        return is;
    }
    
    #endif
    

    Usage:

    #include "streamable_enum.hpp"
    
    using std::cout;
    using std::cin;
    using std::endl;
    
    enum Animal {
        CAT,
        DOG,
        TIGER,
        RABBIT
    };
    
    template <>
    streamable_enum::tostr_map_t get_enum_strings() {
        return {
            { CAT, "Cat"},
            { DOG, "Dog" },
            { TIGER, "Tiger" },
            { RABBIT, "Rabbit" }
        };
    }
    
    int main(int argc, char* argv []) {
        cout << "What animal do you want to buy? Our offering:" << endl;
        for (auto pr : streamable_enum::to_string_map()) {          // Use from_string_map() and pr.first instead
            cout << " " << pr.second << endl;                               // to have them sorted in alphabetical order
        }
        streamable_enum anim;
        cin >> anim;
        if (!cin) {
            cout << "We don't have such animal here." << endl;
        } else if (anim == Animal::TIGER) {
            cout << stream_enum(Animal::TIGER) << " was a joke..." << endl;
        } else {
            cout << "Here you are!" << endl;
        }
    
        return 0;
    }
    

提交回复
热议问题