I have the data structure:
template struct index {};
template struct data {};
template struct X
{
I'll share my approach to this problem which I think is kind of neat. I used C++11 std::conditional
, and C++14 std::integer_sequence
and std::make_integer_sequence
, all of which you can find implementations of online.
Let's start with the data structures you had.
template struct index {};
template struct list {};
template struct pair {};
We'll use a metafunction concat
, which concatenates N
list of types. We use it to filter a list by returning list
when the predicate returns true
, and list<>
otherwise.
For example, to filter the even numbers from list<1, 3, 2, 4, 2>
, we can perform std::conditional_t, list<>>
for each I
to get concat_t
= , list<>, list<2>, list<4>, list<2>>
list<2, 4, 2>
.
template struct concat;
template <> struct concat<> { using type = list<>; }
template
struct concat> { using type = list; };
template
struct concat, list> { using type = list; };
template
struct concat, list, Tail...>
: concat, Tail...> {};
template
using concat_t = typename concat::type;
Now we get to build_index
. We perform bucket sort within the known range of [0, 32)
. We could have used a generic sorting algorithm, but it was more fun to cheat.
template struct build_index;
// e.g., `build_index<
// 1, list, pair<1, 2>, pair<2, 1>, pair<1, 6>, pair<1, 3>>`
template
struct build_index...>> {
// Filter for pairs where `N == lhs`, and replace the `lhs` with the index.
template
static auto filter(std::integer_sequence)
-> concat_t>, list<>>...>;
// e.g., `list, pair<3, 6>, pair<4, 3>>`
using filtered =
decltype(filter(std::make_integer_sequence{}));
// `get(set)` returns the `lhs` if `set` can implicitly convert to
// `pair` for some `lhs`, and nothing otherwise.
template struct set : Ts... {};
template static list> get(pair);
template static list<> get(...);
// We invoke `get` for `I` in `[0, 32)` to sort `filtered`.
template
static auto sort(std::integer_sequence, list)
-> concat_t(set{}))...>;
// e.g., `list, index<4>, index<3>>`
using sorted =
decltype(sort(std::make_integer_sequence{}, filtered{}));
// e.g., `list<1, 4, 3>`
template static index indices(list...>);
using type = decltype(indices(sorted{}));
};
template
using build_index_t = typename build_index::type;
With which we get:
using index_t = build_index_t<
1, list, pair<1, 2>, pair<2, 1>, pair<1, 6>, pair<1, 3>>>;
static_assert(std::is_same, index_t>::value, "");