简体   繁体   English

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

[英]Using part of enum as array index

I have large enum for example: 我有一个大的枚举,例如:

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

I would like to create an array of float numbers using just some of the enum elements. 我只想使用一些枚举元素创建一个float数组。 For example, I would like to have only three elements in array: elem0 , elem7 , elem999 and I would like to acccess them in similar style as this: 例如,我只想在数组中包含三个元素: elem0elem7elem999并且我希望以类似的方式来添加它们:

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

What would be the most elegant way to implement such an array so that array is going to have only three elements ? 什么是实现这种数组以使数组仅包含三个元素的最优雅方法?

Just write a conversion from enum to array index: 只需编写从枚举到数组索引的转换:

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
}

Usage 用法

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

Maybe overkill, but then again maybe not - template expansion can write conversion functions for you. 也许矫kill过正,但也许再也没有-模板扩展可以为您编写转换函数。

This template class allows you to specify which elems should be valid for the vector, and in which order. 使用此模板类,您可以指定哪些元素对矢量有效,并以什么顺序排列。

It also provides the ability to index into the vector by elem, either dynamically (throw exception if does not exists) or statically (fail to compile if out of bounds). 它还提供了通过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;
}

expected output: 预期输出:

0.3, 0.4, 0.5, 
at elem4: 0.4

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM