I need sometimes to filter some types from a given parameter pack and get the result as a std::tuple
. For instance, it can be a filter based on the index of the types in the pack.
As an example, here is a recursive implementation of a stride-like filter, with a semantic similar to std::views::stride
#include <tuple>
namespace pack
{
template<int R, int IDX, typename...ARGS>
struct stride_impl { };
template<int R, int IDX, typename...ARGS>
using stride_impl_t = typename stride_impl<R,IDX,ARGS...>::type;
template<int R, int IDX, typename T, typename...ARGS>
struct stride_impl<R,IDX,T,ARGS...>
{
using type = std::conditional_t <
IDX%R==0,
decltype(std::tuple_cat (
std::tuple<T> {},
stride_impl_t<R,IDX+1,ARGS...> {}
)),
stride_impl_t<R,IDX+1,ARGS...>
>;
};
template<int R, int IDX>
struct stride_impl<R,IDX> { using type = std::tuple<>; };
template<int R, typename...ARGS>
struct stride
{
static_assert(R>0);
using type = stride_impl_t<R,0,ARGS...>;
};
template<int R, typename ...ARGS>
using stride_t = typename stride<R,ARGS...>::type;
};
template<int R> using example = pack::stride_t<R,char,int,long,float,double>;
static_assert (std::is_same_v< example<1>, std::tuple<char,int,long,float,double>>);
static_assert (std::is_same_v< example<2>, std::tuple<char, long, double>>);
static_assert (std::is_same_v< example<3>, std::tuple<char, float >>);
static_assert (std::is_same_v< example<4>, std::tuple<char, double>>);
static_assert (std::is_same_v< example<5>, std::tuple<char >>);
int main() {}
which feels tedious.
Is it possible to have a more direct implementation that avoids explicit recursion (maybe with fold expression)? Perhaps there is something in std
that covers such filters on parameters packs in a similar way to std::views
?
With std::index_sequence
, you might do
namespace pack
{
template<int R, typename...ARGS>
struct stride
{
static_assert(R>0);
using type = decltype([]<std::size_t... Is>(std::index_sequence<Is...>) ->
std::tuple<std::tuple_element_t<Is * R, std::tuple<ARGS...>>...>
{
throw 42;
}(std::make_index_sequence<std::min(sizeof...(ARGS), 1 + (sizeof...(ARGS) - 1) / R)>()));
};
template<int R, typename ...ARGS>
using stride_t = typename stride<R,ARGS...>::type;
};
Demo
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With