Filter a tuple of types in c++17

廉价感情. 提交于 2019-12-11 01:48:26

问题


std::tuple a{1,3,4,5} -> make it to numbers greater than 3

std::tuple b{4,5}    

Or

std::tuple a{
    std::integral_constant<int,1> {},
    std::integral_constant<int,3> {},
    std::integral_constant<int,4> {},
    std::integral_constant<int,5> {} 
}

to

std::tuple a{
    std::integral_constant<int,4>{},
    std::integral_constant<int,5>{}
};

How to convert this at compile time? I can do this using integer_sequence but that is a cumbersome. Is there a simpler way in C++17 using fold expressions or std::apply

Also after filter, also need to get a tuple of unique entries. But my assumption is if filtering can be done, then finding unique would be trivial.

Edit so that is more clear: std::tuple<int_c<1>, int_c<3>,int_c<4>,int_c<5>> to std::tuple<int_c<4>,int_c<5> <-- If such is possible in a concise c++17 way without extra declare functions, it would do!.

Edit: I was fiddling around, maybe something like this would work:

with template... C as the list of integrals constants:

constexpr auto result = std::tuple_cat(std::conditional_t<(C::value > 3), std::tuple<C>, std::tuple<>>{}...);

回答1:


To turn out your tuple_cat with c++17:

constexpr auto result = std::apply([](Ts...) {
    return std::tuple_cat(std::conditional_t<(Ts::value > 3),
                          std::tuple<Ts>,
                          std::tuple<>>{}...);
}, tup);



回答2:


A possible solution is to produce a trait that will output std::tuple<T> for desirable elements T and std::tuple<> for undesirable elements and to use std::tuple_cat to recombine those tuples into a single type. For example :

#include <tuple>
#include <type_traits>
#include <utility>

template <typename Pred, typename Tuple> struct filter;

template <typename t_Predicate, typename ...Ts> 
struct filter<t_Predicate, std::tuple<Ts...>>
{
    // If this element has to be kept, returns `std::tuple<Ts>`
    // Otherwise returns `std::tuple<>`
    template<class E>
    using t_filter_impl = std::conditional_t<
        t_Predicate<E>::value,
        std::tuple<E>, std::tuple<>>;

    // Determines the type that would be returned by `std::tuple_cat`
    //  if it were called with instances of the types reported by 
    //  t_filter_impl for each element
    using type = decltype(std::tuple_cat(std::declval<t_filter_impl<Ts>>()...));
};

Where t_Predicate<T> is any predicate type with a bool value; member which determines whether or not T is a desirable type. For example to apply this solution to the original question, first write a predicate type specialized for std::integral_constant :

// Non integral_constant are not kept
template<class T>
struct four_or_more : std::integral_constant<bool, false> {};

// integral_const types are kept if their value is >=4
template<class T, T V>
struct four_or_more<std::integral_constant<T, V>> :
    std::integral_constant<bool, V >= 4> {};

And here is a demonstration :

#include <iostream>

int main()
{
    auto a = std::make_tuple(
        std::integral_constant<int,1> {},
        std::integral_constant<int,3> {},
        std::integral_constant<int,4> {},
        std::integral_constant<int,5> {}
    );

    using b_type = filter<four_or_more, decltype(a)>::type;

    std::cout << "size : " << std::tuple_size<b_type>() << std::endl;
    std::cout << std::tuple_element_t<0, b_type>::value << std::endl;
    std::cout << std::tuple_element_t<1, b_type>::value << std::endl;
}



回答3:


You can do that with new STL utilities from C++17. That would be something like that:

template<typename T>
auto filter(T tup) {
    return std::apply([](auto first, auto... rest) {
        auto filtered_rest = [](){
            if constexpr (sizeof...(rest)) {
                return filter(std::tuple{rest...});
            } else {
                return std::tuple{};
            }
        }();

        if constexpr (first > 3) {
            return std::tuple_cat(std::tuple{first}, filtered_rest);
        } else {
            return filtered_rest;
        }
    }, tup);
}

Of course, there is many other ways to do it. In this case I used std::apply and recursion. I start by an empty tuple and I add one element at a time.



来源:https://stackoverflow.com/questions/50971320/filter-a-tuple-of-types-in-c17

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!