How to filter a std::integer_sequence

前端 未结 3 1691
一个人的身影
一个人的身影 2021-01-06 01:49

If I theoretically have a sequence of integers like

std::integer_sequence

How can I filter it with

3条回答
  •  执笔经年
    2021-01-06 02:23

    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.

提交回复
热议问题