[英]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>
为期望的元素T
和std::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.