This requires some template.
template<size_t I, class Indexes>
struct offset_indexes;
template<size_t I, class Indexes>
using offset_indexes_t = typename offset_indexes<I,Indexes>::type;
template<size_t I, size_t...Is>
struct offset_indexes<I, std::index_sequence<Is...>> {
using type=std::index_sequence<(I+Is)...>;
};
then binary fold:
template<size_t...Is, class Tuple>
constexpr auto retuple( std::index_sequence<Is...>, Tuple&& tuple ) {
return std::forward_as_tuple( std::get<Is>(std::forward<Tuple>(tuple))... );
}
template<class F, class T>
constexpr T binary_fold( F&& f, std::tuple<T>&& tuple ) {
return std::get<0>(std::move(tuple));
}
template<class Tuple>
struct first_element {};
template<class Tuple>
using first_element_t=typename first_element<Tuple>::type;
template<template<class...>class Z, class T0, class...Ts>
struct first_element<Z<T0,Ts...>>{using type=T0;};
template<class F, class Tuple, class E=first_element_t<std::decay_t<Tuple>>>
constexpr std::decay_t<E> binary_fold( F&& f, Tuple&& tuple ) {
constexpr auto count = std::tuple_size<std::decay_t<Tuple>>{};
using first_half = std::make_index_sequence< count/2 >;
using second_half = offset_indexes_t<
count/2,
std::make_index_sequence< (count+1)/2 >
>;
return f(
binary_fold( f, retuple( first_half{}, std::forward<Tuple>(tuple) ) ),
binary_fold( f, retuple( second_half{}, std::forward<Tuple>(tuple) ) )
);
}
which should make a binary tree of recursive calls binary_fold.
All this simplifies count_bits:
template <class...Ms>
constexpr size_t count_bits(Ms&&...ms)
{
return binary_fold(
std::plus<>{},
std::make_tuple(n_active_bits(std::forward<Ms>(ms))...)
);
}
Note, however, that there are many patterns.
, / .
.