c++ - 将与谓词匹配的相邻元组元素分组为子元组

标签 c++ tuples c++17 metaprogramming

给定一些元素和谓词的元组,如何将与谓词匹配的相邻元素分组到子元组中?

一个例子:

#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";
}

这个想法很简单,但是有很多模板样板。

Compiler Explorer Link

关于c++ - 将与谓词匹配的相邻元组元素分组为子元组,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60627048/

相关文章:

c++ - 用整数读取一行 C++

python - Python 中的 "named tuples"是什么?

c++ - 如何在二维数组上随机放置 2 个唯一点?

c++ - 合并两个 std::set 和(尚未) std::set::merge()

python - 将列表列表转换回元组列表

scala - 如何扁平化嵌套元组?

c++ - std::vector 范围构造函数可以调用显式转换吗?

c++ - 关于在丢弃的 if constexpr(false) 语句中实例化模板时,编译器之间的行为不一致

c++ - 类模板的内部类的类元组结构化绑定(bind)

c++ - 在课后使用 typedef ClassName< >