使用枚举的一部分作为数组索引

时间:2017-03-24 18:28:41

标签: c++ arrays c++11 enums

我有大枚举例如:

enum { elem0, elem1, elem2, elem3 ...... elem1000 }

我想使用一些枚举元素创建一个float数字数组。 例如,我想在数组中只有三个元素:elem0elem7elem999,我想以类似的方式对它们进行处理:

array[elem0]=123
array[elem7]=12.5
array[elem999]=15.6

实现这样一个数组的最优雅的方法是什么,以便数组只有三个元素?

2 个答案:

答案 0 :(得分:2)

只需编写从枚举到数组索引的转换:

int EnumToIdx(Elem elem)
{
    switch (elem)
    {
        case elem0: return 0;
        case elem7: return 1;
        case elem999: return 2;
    }

    throw std::invalid_argument("EnumToIdx: no conversion"); // or whatever
}

用法

array[EnumToIdx(elem0)] = 123;
array[EnumToIdx(elem7)] = 12.5;
array[EnumToIdx(elem999)] = 15.6;

答案 1 :(得分:0)

也许是矫枉过正,但也许不是 - 模板扩展可以为你编写转换函数。

此模板类允许您指定哪些元素应对矢量有效,以及按顺序排列。

它还提供了通过elem索引向量的能力,动态(如果不存在则抛出异常)或静态(如果超出界限则无法编译)。

#include <array>
#include <iostream>
#include <algorithm>
#include <iterator>
#include <stdexcept>


//
// boilerplate
//

namespace notstd {
    template<class T, class Tuple>
    struct tuple_index;

    template<class T, class... Types>
    struct tuple_index<T, std::tuple<T, Types...>> {
        using type = std::size_t;
        static const type value = 0;
    };

    template<class T, class U, class... Types>
    struct tuple_index<T, std::tuple<U, Types...>> {
        using type = std::size_t;
        static const type value = 1 + tuple_index<T, std::tuple<Types...>>::value;
    };
}

enum element_type {
    elem0, elem1, elem2, elem3, elem4, elem5, elem1000
};


template<element_type Value>
struct where_type
{
    static const element_type value = Value;
};

template<element_type Value>
static constexpr auto where = where_type<Value> {};

template<element_type...Permitted>
struct restricted_vector : private std::array<double, sizeof...(Permitted)> {
    using corresponding_tuple = std::tuple<where_type<Permitted>...>;
    using inherited = std::array<double, sizeof...(Permitted)>;

    using inherited::inherited;


    static auto conversion(element_type e) -> std::size_t
    {
        static const std::array<std::pair<element_type, std::size_t>, sizeof...(Permitted)> a = {
                std::make_pair(Permitted, notstd::tuple_index<where_type<Permitted>, corresponding_tuple>::value)...
        };
        auto ifind = std::find_if(a.begin(), a.end(), [e](auto&& elem) { return elem.first == e; });
        if (ifind == a.end()) {
            throw std::out_of_range("invalid element");
        }
        return ifind->second;
    }

    template<element_type Elem>
    auto& operator[](where_type<Elem>) {
        auto pos = notstd::tuple_index<where_type<Elem>, corresponding_tuple >::value;
        return inherited::operator[](pos);
    }

    template<element_type Elem>
    auto const& operator[](where_type<Elem>) const {
        auto pos = notstd::tuple_index<where_type<Elem>, corresponding_tuple >::value;
        return inherited::operator[](pos);
    }

    // dynamic access
    auto& at(element_type e) {
        return inherited::operator[](conversion(e));
    }

    auto const& at(element_type e) const {
        return inherited::operator[](conversion(e));
    }

    using inherited::begin;
    using inherited::end;
    using inherited::size;  // etc
};


int main() {
    auto v1 = restricted_vector<elem3, elem4, elem5> {};

    v1[where<elem4>] = 0.4;
    v1[where<elem5>] = 0.5;
    v1[where<elem3>] = 0.3;

    std::copy(v1.begin(), v1.end(), std::ostream_iterator<double>(std::cout, ", "));
    std::cout << "\n";

    std::cout << "at elem4: " << v1.at(elem4) << std::endl;
}

预期产出:

0.3, 0.4, 0.5, 
at elem4: 0.4