Iterating over non-incremental Enum

前端 未结 15 1701
长发绾君心
长发绾君心 2021-01-31 15:42

Before you ask, I\'ve looked and looked for this on SO, and cannot find a solid answer.

I need to be able to dynamically iterate over an enum that has non-incre

15条回答
  •  后悔当初
    2021-01-31 16:22

    the beginnings of a solution involving no macros and (almost) no runtime overhead:

    #include 
    #include 
    #include 
    #include 
    
    template using has_value = std::integral_constant;
    
    template
    struct better_enum
    {
        static constexpr size_t size = sizeof...(EnumValues);
        using value_array = int[size];
        static const value_array& values() {
            static const value_array _values = { EnumValues::value... };
            return _values;
        }
        using name_array = const char*[size];
        static const name_array& names() {
            static const name_array _names = { EnumValues::name()... };
            return _names;
        }
    
    
        using enum_values = boost::mpl::vector;
    
        struct iterator {
            explicit iterator(size_t i) : index(i) {}
    
            const char* name() const {
                return names()[index];
            }
            int value() const {
                return values()[index];
            }
            operator int() const {
                return value();
            }
    
            void operator++() {
                ++index;
            }
            bool operator==(const iterator& it) const {
                return index == it.index;
            }
            bool operator!=(const iterator& it) const {
                return index != it.index;
            }
            const iterator& operator*() const {
                return *this;
            }
        private:
            size_t index;
        };
        friend std::ostream& operator<<(std::ostream& os, const iterator& iter)
        {
            os << "{ " << iter.name() << ", " << iter.value() << " }";
            return os;
        }
    
        template
        static iterator find() {
            using iter = typename boost::mpl::find::type;
            static_assert(iter::pos::value < size, "attempt to find a value which is not part of this enum");
            return iterator { iter::pos::value };
        }
    
        static iterator begin() {
            return iterator { 0 };
        }
    
        static iterator end() {
            return iterator { size };
        }
    
    };
    
    struct Pig : has_value<0> { static const char* name() { return "Pig";} };
    struct Dog : has_value<7> { static const char* name() { return "Dog";} };
    struct Cat : has_value<100> { static const char* name() { return "Cat";} };
    struct Horse : has_value<90> { static const char* name() { return "Horse";} };
    
    struct Monkey : has_value<1000> { static const char* name() { return "Monkey";} };
    
    using animals = better_enum<
    Pig,
    Dog,
    Cat,
    Horse
    >;
    
    using namespace std;
    
    auto main() -> int
    {
        cout << "size : " << animals::size << endl;
        for (auto v : animals::values())
        cout << v << endl;
    
        for (auto v : animals::names())
        cout << v << endl;
    
        cout << "full iteration:" << endl;
        for (const auto& i : animals())
        {
            cout << i << endl;
        }
    
        cout << "individials" << endl;
        auto animal = animals::find();
        cout << "found : " << animal << endl;
        while (animal != animals::find()) {
            cout << animal << endl;
            ++animal;
        }
    
    // will trigger the static_assert    auto xx = animals::find();
    
        return 0;
    }
    

    output:

    size : 4
    0
    7
    100
    90
    Pig
    Dog
    Cat
    Horse
    full iteration:
    { Pig, 0 }
    { Dog, 7 }
    { Cat, 100 }
    { Horse, 90 }
    individials
    found : { Dog, 7 }
    { Dog, 7 }
    { Cat, 100 }
    

提交回复
热议问题