将与谓词匹配的相邻元组元素分组为子元组
Group adjacent tuple elements matching a predicate into sub-tuples
给定一些元素的元组和谓词,如何将与谓词匹配的相邻元素分组为子元组?
一个例子:
#include <tuple>
auto is_float = [](auto x) {
return std::is_same<decltype(x), float>{};
};
int main() {
auto tup = std::tuple{1.f, 2.f, 3, 4, 5.f, 6.f, 7};
auto result = magic_foo(is_float, tup);
// all adjacent floats are grouped into sub-tuples like this:
auto expected = std::tuple{std::tuple{1.f, 2.f}, 3, 4, std::tuple{5.f, 6.f}, 7};
assert(tup == expected);
}
一个非常粗糙的实现:
#include <type_traits>
#include <tuple>
#include <typeinfo>
#include <iostream>
template <typename ... T1, typename ... T2, std::size_t ... I1, std::size_t ... I2>
auto concat_tuple(const std::tuple<T1...>& t1, const std::tuple<T2...>& t2, std::index_sequence<I1...>, std::index_sequence<I2...>) {
return std::tuple<T1..., T2...>(
std::get<I1>(t1)...,
std::get<I2>(t2)...
);
}
template <typename ... T1, typename ... T2>
auto concat_tuple(const std::tuple<T1...>& t1, const std::tuple<T2...>& t2) {
return concat_tuple(t1, t2,
std::make_index_sequence<sizeof...(T1)>{},
std::make_index_sequence<sizeof...(T2)>{}
);
}
template <typename ... T, std::size_t ... I>
auto tuple_rest(const std::tuple<T...>& tup, std::index_sequence<I...>) {
return std::make_tuple(std::get<I+1>(tup)...);
}
template <typename ... T>
auto tuple_rest(const std::tuple<T...>& tup) {
return tuple_rest(tup, std::make_index_sequence<sizeof...(T) - 1>{});
}
template <template <typename T> class Pred, typename ... TAcc>
auto group_by_pred(std::tuple<TAcc...> acc, std::tuple<> tup) {
if constexpr (sizeof...(TAcc) == 0u) {
return std::make_tuple();
}
else return std::make_tuple(acc);
}
template <template <typename T> class Pred, typename ... TAcc, typename T0, typename ... T>
auto group_by_pred(std::tuple<TAcc...> acc, std::tuple<T0, T...> tup) {
if constexpr (Pred<T0>::value) {
return group_by_pred<Pred>(
concat_tuple(acc, std::make_tuple(std::get<0>(tup))),
tuple_rest(tup)
);
}
else {
if constexpr (sizeof...(TAcc) == 0u) {
return concat_tuple(
std::make_tuple(),
concat_tuple(
std::make_tuple(std::get<0>(tup)),
group_by_pred<Pred>(std::make_tuple(), tuple_rest(tup))
)
);
}
else return concat_tuple(
std::make_tuple(acc),
concat_tuple(
std::make_tuple(std::get<0>(tup)),
group_by_pred<Pred>(std::make_tuple(), tuple_rest(tup))
)
);
}
}
template <typename T>
struct not_int : std::true_type {};
template <>
struct not_int<int> : std::false_type {};
int main() {
auto tup = std::make_tuple(1, 2.0, 3.0, 2, 3.0);
auto result = group_by_pred<not_int>(std::make_tuple(), tup);
std::cout << typeid(result).name() << "\n";
}
想法很简单,但是模板样板很多。
给定一些元素的元组和谓词,如何将与谓词匹配的相邻元素分组为子元组?
一个例子:
#include <tuple>
auto is_float = [](auto x) {
return std::is_same<decltype(x), float>{};
};
int main() {
auto tup = std::tuple{1.f, 2.f, 3, 4, 5.f, 6.f, 7};
auto result = magic_foo(is_float, tup);
// all adjacent floats are grouped into sub-tuples like this:
auto expected = std::tuple{std::tuple{1.f, 2.f}, 3, 4, std::tuple{5.f, 6.f}, 7};
assert(tup == expected);
}
一个非常粗糙的实现:
#include <type_traits>
#include <tuple>
#include <typeinfo>
#include <iostream>
template <typename ... T1, typename ... T2, std::size_t ... I1, std::size_t ... I2>
auto concat_tuple(const std::tuple<T1...>& t1, const std::tuple<T2...>& t2, std::index_sequence<I1...>, std::index_sequence<I2...>) {
return std::tuple<T1..., T2...>(
std::get<I1>(t1)...,
std::get<I2>(t2)...
);
}
template <typename ... T1, typename ... T2>
auto concat_tuple(const std::tuple<T1...>& t1, const std::tuple<T2...>& t2) {
return concat_tuple(t1, t2,
std::make_index_sequence<sizeof...(T1)>{},
std::make_index_sequence<sizeof...(T2)>{}
);
}
template <typename ... T, std::size_t ... I>
auto tuple_rest(const std::tuple<T...>& tup, std::index_sequence<I...>) {
return std::make_tuple(std::get<I+1>(tup)...);
}
template <typename ... T>
auto tuple_rest(const std::tuple<T...>& tup) {
return tuple_rest(tup, std::make_index_sequence<sizeof...(T) - 1>{});
}
template <template <typename T> class Pred, typename ... TAcc>
auto group_by_pred(std::tuple<TAcc...> acc, std::tuple<> tup) {
if constexpr (sizeof...(TAcc) == 0u) {
return std::make_tuple();
}
else return std::make_tuple(acc);
}
template <template <typename T> class Pred, typename ... TAcc, typename T0, typename ... T>
auto group_by_pred(std::tuple<TAcc...> acc, std::tuple<T0, T...> tup) {
if constexpr (Pred<T0>::value) {
return group_by_pred<Pred>(
concat_tuple(acc, std::make_tuple(std::get<0>(tup))),
tuple_rest(tup)
);
}
else {
if constexpr (sizeof...(TAcc) == 0u) {
return concat_tuple(
std::make_tuple(),
concat_tuple(
std::make_tuple(std::get<0>(tup)),
group_by_pred<Pred>(std::make_tuple(), tuple_rest(tup))
)
);
}
else return concat_tuple(
std::make_tuple(acc),
concat_tuple(
std::make_tuple(std::get<0>(tup)),
group_by_pred<Pred>(std::make_tuple(), tuple_rest(tup))
)
);
}
}
template <typename T>
struct not_int : std::true_type {};
template <>
struct not_int<int> : std::false_type {};
int main() {
auto tup = std::make_tuple(1, 2.0, 3.0, 2, 3.0);
auto result = group_by_pred<not_int>(std::make_tuple(), tup);
std::cout << typeid(result).name() << "\n";
}
想法很简单,但是模板样板很多。