简体   繁体   English

在 c++17 中过滤类型的元组

[英]Filter a tuple of types in c++17

std::tuple a{1,3,4,5} -> make it to numbers greater than 3 std::tuple a{1,3,4,5} -> 使其成为大于 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.我可以使用integer_sequence来做到这一点,但这很麻烦。 Is there a simpler way in C++17 using fold expressions or std::apply在 C++17 中是否有更简单的方法使用折叠表达式或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!.编辑以便更清楚: std::tuple<int_c<1>, int_c<3>,int_c<4>,int_c<5>> to std::tuple<int_c<4>,int_c<5> <--如果可以在没有额外声明函数的情况下以简洁的 c++17 方式做到这一点,那就行了!

Edit: I was fiddling around, maybe something like this would work:编辑:我在摆弄,也许这样的事情会奏效:

with template... C as the list of integrals constants:使用template... C作为积分常数列表:

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

To turn out your tuple_cat with c++17:用 c++17 生成你的tuple_cat

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

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.一种可能的解决方案是产生一个特点在于将输出std::tuple<T>为期望的元素Tstd::tuple<>对不需要的元素和使用std::tuple_cat那些元组重新组合成一个单一的类型。 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;其中t_Predicate<T>是具有bool value;任何谓词类型bool value; member which determines whether or not T is a desirable type.成员决定T是否是理想的类型。 For example to apply this solution to the original question, first write a predicate type specialized for std::integral_constant :例如,将此解决方案应用于原始问题,首先编写一个专用于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;
}

You can do that with new STL utilities from C++17.您可以使用来自 C++17 的新 STL 实用程序来做到这一点。 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.在这种情况下,我使用了std::apply和递归。 I start by an empty tuple and I add one element at a time.我从一个空元组开始,一次添加一个元素。

Live example: https://godbolt.org/z/qo63r4实例: https : //godbolt.org/z/qo63r4

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM