C++14 将元组扩展三乘三

C++14 expand a tuple three by three

本文关键字:扩展 元组 C++14      更新时间:2023-10-16

我有一个大小为 3 的倍数的 C++14 元组,我想按顺序将其扩展 3 x 3 到一个函数。

tuple<int, int, int, int, int, int> a(1, 2, 4, 6, 7, 2);
void process_triplet(int& mystate, int a, int b, int c) {
// do something on a b c and mystate
}
template <typename Tuple>
void process_triplets(Tuple&& tuple) {
// how do I write over here such that I can 'sequentially' processing each triplet
// ideally I want the following:
// process_triplet(mystate, 1, 2, 3);
// process_triplet(mystate, 4, 5, 6);
}

需要帮助以通用方式实施process_triplets

好吧,你需要一个std::index_sequence和包扩展:

template <class Tuple, std::size_t... N>
void process_triplets_impl(int& mystate, Tuple&& tuple, std::index_sequence<N...>) {
int x[] = {
0,
((void)process_triplet(
mystate,
std::get<N * 3 + 0>(std::forward<Tuple>(tuple)),
std::get<N * 3 + 1>(std::forward<Tuple>(tuple)),
std::get<N * 3 + 2>(std::forward<Tuple>(tuple))
), 0)
...
};
(void)x;
}
template <class Tuple>
void process_triplets(int& mystate, Tuple&& tuple) {
process_triplets_impl(
mystate
std::forward<Tuple>(tuple),
std::make_index_sequence<std::tuple_size<std::decay_t<Tuple>>::value / 3>()
);
}

方法一

这是一种简单、直接和递归的方法,涉及将元组从上层传递到下层阶段,而无需前三个元组元素。

#include <tuple>
std::tuple<int, int, int, int, int, int> a(1, 2, 4, 6, 7, 2);
void ProcessTriplet(int a, int b, int c) { printf("%d, %d, %dn", a, b, c); }
template <typename... Args, size_t... Ints>
void ProcessTripletsHelper(const std::tuple<int, int, int, Args...>& tuple,
std::index_sequence<Ints...>) {
using NextTupleType = std::tuple<Args...>;
NextTupleType next_tuple = {std::get<Ints + 3>(tuple)...};
ProcessTriplet(std::get<0>(tuple), std::get<1>(tuple), std::get<2>(tuple));
ProcessTripletsHelper(
next_tuple,
std::make_index_sequence<std::tuple_size_v<NextTupleType> - 3>{});
}
template <>
void ProcessTripletsHelper<>(const std::tuple<int, int, int>& tuple,
std::index_sequence<>) {
ProcessTriplet(std::get<0>(tuple), std::get<1>(tuple), std::get<2>(tuple));
}
template <typename Tuple>
void ProcessTriplets(Tuple&& tuple) {
ProcessTripletsHelper(
std::forward<Tuple>(tuple),
std::make_index_sequence<
std::tuple_size_v<std::remove_reference_t<Tuple>> - 3>{});
}
int main() {
ProcessTriplets(a);
return 0;
}

方法二

在这里,我提出了另一种性能更好的方法(没有运行时复制,模板编译器的负担更小(和更容易实现(不需要std::index_sequence和更少的代码行(。constexpr在这里至关重要,因为它可以防止在类型推导结束时进行进一步编译。

#include <tuple>
std::tuple<int, int, int, int, int, int> a(1, 2, 4, 6, 7, 2);
void ProcessTriplet(int a, int b, int c) { printf("%d, %d, %dn", a, b, c); }
template <size_t First, typename Tuple>
void ProcessTripletsHelper(Tuple&& tuple) {
ProcessTriplet(std::get<First>(tuple), std::get<First + 1>(tuple),
std::get<First + 2>(tuple));
if constexpr (First + 3 ==
std::tuple_size_v<std::remove_reference_t<Tuple>>) {
} else {
ProcessTripletsHelper<First + 3, Tuple>(std::forward<Tuple>(tuple));
}
}
template <typename Tuple>
void ProcessTriplets(Tuple&& tuple) {
ProcessTripletsHelper<0, Tuple>(std::forward<Tuple>(tuple));
}
int main() {
ProcessTriplets(a);
return 0;
}