Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Type function that returns a tuple of chosen types

I've implemented a type function Tuple that turn a list of My_enum values into an std::tuple of corresponding types:

#include <tuple>

enum My_enum{ t_int, t_double };

// Bind_type is a type function that given a My_enum returns the corresponding type
template<My_enum E> struct Bind_type;
template<> struct Bind_type<t_int>{ using type = int; };
template<> struct Bind_type<t_double>{ using type = double; };

// Tuple is a type function that given a template value parameter pack of My_enums returns a std::tuple of correspondig types
template<My_enum First, My_enum... Others>
struct Tuple {
    using type = decltype(std::tuple_cat(
                typename Tuple<First>::type{},
                typename Tuple<Others...>::type{}
            ));
};

template<>
struct Tuple<t_int> {
    using type = std::tuple<Bind_type<t_int>::type>;
};
template<>
struct Tuple<t_double> {
    using type = std::tuple<Bind_type<t_double>::type>;
};

I'd like to be able to declare the recursion base case for Tuple in one shot, because I don't want to manually manage Tuple specialization as long as I add or remove values to My_enum, because it is error prone (and boring). I've tried:

template<My_enum E>
struct Tuple {
    using type = std::tuple<Bind_type<E>::type>;
};

but this is not a valid specialization for the variadic version.

My question is: is there a smart way to declare the specialization of Tuple when it has only one template value parameter?

like image 667
Paolo M Avatar asked Jun 22 '15 11:06

Paolo M


1 Answers

You can do this without recursion by simply expanding the parameter pack directly into a std::tuple:

template<My_enum... Enums>
struct Tuple {
    using type = std::tuple<typename Bind_type<Enums>::type...>;
};

To answer your question more directly, you can declare a variadic primary template, then write two specializations: for when there are at least two parameters, and for when there is only one:

//primary template, takes any number of My_enums
template <My_enum... Enums>
struct Tuple {
    //this case will be chosen if we instantiate a Tuple with no args
    using type = std::tuple<>;
}

//specialization for when there are at least two arguments
template<My_enum First, My_enum Second, My_enum... Others>
struct Tuple<First,Second,Others...> {
    using type = decltype(std::tuple_cat(
                typename Tuple<First>::type{},
                typename Tuple<Second,Others...>::type{}
            ));
};

//base case, only one argument left
template<My_enum Last>
struct Tuple<Last> {
    using type = std::tuple<typename Bind_type<Last>::type>;
};
like image 84
TartanLlama Avatar answered Sep 22 '22 15:09

TartanLlama