【问题标题】:Using part of enum as array index使用枚举的一部分作为数组索引
【发布时间】:2017-03-24 18:28:41
【问题描述】:

例如,我有很大的枚举:

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

我想只使用一些枚举元素创建一个float 数字数组。 例如,我希望数组中只有三个元素:elem0elem7elem999,并且我想以类似的方式访问它们:

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

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

【问题讨论】:

  • 你的问题是?
  • 实现这样一个数组的最优雅的方法是什么,这样数组将只有三个元素。
  • @Egon 你考虑过std::map吗?
  • @Egon 请详细说明:为什么std::map 对您的用例来说太重了?

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


【解决方案1】:

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

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;

【讨论】:

    【解决方案2】:

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

    这个模板类允许你指定哪些元素应该对向量有效,以及以什么顺序。

    它还提供了通过 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
    

    【讨论】:

    • 现在我们知道,当 C++ 被指责过于复杂时,谁该归咎于个人。
    • @Rost 计算机科学总是很复杂。我们希望用户代码越简单、越安全,我们在实现它将使用的服务时就必须越复杂。希望可以看出,上面的代码允许用户使用任意选择的枚举值创建一个受限制的向量,而无需额外的工作或维护。
    猜你喜欢
    • 2010-09-29
    • 2016-06-26
    • 1970-01-01
    • 2010-11-02
    • 2019-11-17
    • 2022-08-15
    • 2012-03-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多