2

I have an extendable collection of classes that have approximately the same interface, that each have a different static constant for serialization purposes. Consider:

class A {
    constexpr static int value = 0;
};

class B {
    constexpr static int value = 1;
};

Now, I'd like to do a reverse mapping from value to the class itself. I can do:

template <int value> struct type_for_value { };
template <> struct type_for_value<0> { using type = A; };
template <> struct type_for_value<1> { using type = B; };

This works, however, every time I add a class to the collection (say class C), I have to add another template specialization. I also have other functions that use the entire collection of classes, such as:

constexpr auto for_each_class(auto const& func) {
    return func.template operator()<A, B>;
}

Here I'd also need to add C to the parameter pack.

Is there any way to define the collection of classes once (maybe a macro, but preferably using something better typed like a single parameter pack), such that the template specializations are automatically generated at compile time, and that I can also use in the for_each_class function?

I tried to create a single struct with a parameter pack, like this:

template <typename... T>
struct all_classes_impl {
    constexpr static auto for_each_class(auto const& func) {
        return func.template operator()<T...>();
    }

    template <int value>
    struct type_for_value { };

    template <>
    struct type_for_value<T::type> {
        using type = T;
    }...;
}

using all_classes = all_classes_impl<A, B>;
constexpr auto for_each_class = &all_classes::for_each_class;

But this doesn't work for the template specializations, and aliasing the for_each_class also does not work in this way.

Mark
  • 31
  • 4

1 Answers1

2

With a single point that needs to be edited if you add classes you can do this fairly minimally like

using type_list = std::tuple<A, B>;

template<int value>
using type_for_value_t = typename std::tuple_element<value, type_list>::type;

and then you can use it like

type_for_value_t<1> my_var;

and my_var will have the type B.

The only thing you need to maintain here is that the order of the types in type_list so that they are in the same index as their value. This does mean you either need contiguous values or you add dummy types to the tuple where you have a hole.

NathanOliver
  • 171,901
  • 28
  • 288
  • 402