I would like to transform a compile time list of lists of types into a list of lists of std::integral_constant
indices.
Appearently this requires some kind of 2d iota-like transformation.
Example source
template<typename... Ts> struct type_list{};
using L = type_list<
type_list<>,
type_list<>,
type_list<>,
type_list<>,
type_list<int>,
type_list<>,
type_list<int>,
type_list<int>,
type_list<int>,
type_list<int,double>,
type_list<int,double>
>;
expected result
template<uint64_t V> using I = std::integral_constant<uint64_t, V>; // alias for better legibility
using R = type_list<
type_list<>,
type_list<>,
type_list<>,
type_list<>,
type_list<I<0>>,
type_list<>,
type_list<I<1>>,
type_list<I<2>>,
type_list<I<3>>,
type_list<I<4>, I<5>>,
type_list<I<6>, I<7>>
>;
I think boost::mp11
fits this purpose perfectly, but I lack the experience to bring it all together. Please share your advice.
I think boost::mp11 fits this purpose perfectly, but I lack the experience to bring it all together. Please share your advice.
You are correct! Boost.Mp11 does fit this purpose perfectly.
This is basically a stateful fold. We have to keep track of how many values we've pushed so far, call that N
. Then, for each new element of the list, L
, that we're iterating on, we append a new list that is [N, N+1, ..., N+len(L)-1]
and then do N += len(L)
in the state.
For convenience, we can add a State
:
template <class N, class L>
struct State {
using value = N;
using list = L;
};
An accumulating function that does what I described above:
template <class S, class L>
using F = State<
// S::value + len(L)
mp_plus<typename S::value, mp_size<L>>,
mp_push_back<typename S::list,
// iota just gives you [0, 1, ..., V-1]
// so we need to add S::value to all of those
mp_transform_q<
mp_bind_front<mp_plus, typename S::value>,
mp_iota<mp_size<L>>>>
>;
And then lastly, we do the fold
and pull out the list
:
template <class L>
using types_to_ints = mp_fold<L, State<mp_size_t<0>, mp_list<>>, F>::list
Example demonstrating that it does the right thing.