If I theoretically have a sequence of integers like
std::integer_sequence
How can I filter it with
An alternative solution leveraging tuples:
template
struct filter_integer_sequence_impl
{
template
static constexpr auto Unpack(std::tuple)
{
return std::integer_sequence();
}
template
using Keep = std::tuple>;
using Ignore = std::tuple<>;
using Tuple = decltype(std::tuple_cat(std::conditional_t<(*Pred)(I), Keep, Ignore>()...));
using Result = decltype(Unpack(Tuple()));
};
template
constexpr auto filter_integer_sequence(std::integer_sequence)
{
return typename filter_integer_sequence_impl::Result();
}
template
constexpr auto filter_integer_sequence(std::integer_sequence sequence, Pred)
{
return filter_integer_sequence<(Pred*)nullptr>(sequence);
}
Used like this:
constexpr auto predicate = [](int val) { return (val % 2) == 0; };
constexpr auto start = std::integer_sequence();
constexpr auto filtered = filter_integer_sequence(start, predicate);
constexpr auto expected = std::integer_sequence();
static_assert(std::is_same_v);
The second overload of filter_integer_sequence
is only necessary for C++17 which doesn't allow us to use lambdas for non-type template parameters. C++20 lifts that restriction, so in that case only the first overload is needed. Note that the first overload is still necessary in C++17 for handling regular function pointers.
Like the other solutions here, the second overload only works for non-capturing lambdas. This is why we can safely evaluate (*(Pred*)nullptr)(I)
as constexpr since the lambda body doesn't actually use the this
pointer.