1

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. 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:

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 ?

max66
  • 65,235
  • 10
  • 71
  • 111
Egon
  • 11
  • 1

2 Answers2

3

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;
Stas
  • 11,571
  • 9
  • 40
  • 58
0

Maybe overkill, but then again maybe not - template expansion can write conversion functions for you.

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).

#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
Richard Hodges
  • 68,278
  • 7
  • 90
  • 142
  • 1
    Now we know who is to blame personally when C++ is accused of over-complexity. – Rost Mar 25 '17 at 08:58
  • @Rost there is always complexity in computer science. The simpler and safer we wish user code to be, the more complexity we must put in the implementation of the services it will use. Hopefully, it can be seen that the code above allows the user to create a restricted_vector using any arbitrary selection of enum values with no extra work or maintenance. – Richard Hodges Mar 25 '17 at 09:59