[英]How to implement a variadic tuple_map operation?
我想要實現一個函數,該函數將給定函數的元組的可變列表映射到另一個元組。
它將N元函數f
應用於從N個元組的列表中獲取的元素列表(每個元組的大小至少為M),並根據這些應用程序的結果創建一個新的M元素元組。
對於N個元組的列表,每個元組包含M個元素,對std::make_tuple
的調用將類似於以下偽代碼:
std::make_tuple(
f(t1_1, t2_1, t3_1, ..., tN_1),
f(t1_2, t2_2, t3_2, ..., tN_2),
f(t1_3, t2_3, t3_3, ..., tN_3),
...
f(t1_M, t2_M, t3_M, ..., tN_M)
)
有時,此操作在其他語言中稱為zipWith
。
我希望此函數tuple_map
具有以下簽名:
template<class Tuple1, class... Tuples2, class Function>
auto tuple_map(Tuple1&& tuple1, Tuples&&... tuples, Function f);
我想出了一個采用單個元組的函數的實現:
#include <tuple>
#include <integer_sequence>
#include <type_traits>
#include <utility>
template<class Tuple, class Function, size_t... I>
auto tuple_map_impl(Tuple&& t, Function f, std::index_sequence<I...>)
-> decltype(
std::make_tuple(
f(std::get<I>(std::forward<Tuple>(t)))...
)
)
{
return std::make_tuple(
f(std::get<I>(std::forward<Tuple>(t)))...
);
}
template<class Tuple, class Function>
auto tuple_map(Tuple&& t, Function f)
-> decltype(
tuple_map_impl(
std::forward<Tuple>(t),
f,
std::make_index_sequence<
std::tuple_size<std::decay_t<Tuple>>::value
>()
)
)
{
using indices = std::make_index_sequence<
std::tuple_size<std::decay_t<Tuple>>::value
>;
return tuple_map_impl(std::forward<Tuple>(t), indices());
}
當我除了I...
引入另一個參數包( Tuples
)時,它會引起問題:
template<class Tuple1, class... Tuples, class Function, size_t... I>
auto tuple_map_impl(Tuple1&& tuple1, Tuples&&... tuples, Function f, std::index_sequence<I...>)
-> decltype(
std::make_tuple(
f(
std::get<I>(std::forward<Tuple1>(t1)),
std::get<I>(std::forward<Tuples>(tuples))...
)...
)
)
{
return std::make_tuple(
f(
std::get<I>(std::forward<Tuple>(t)),
std::get<I>(std::forward<Tuples>(tuples))...
)...
);
}
編譯器錯誤:
error: mismatched argument pack lengths while expanding ‘get<I>(forward<Tuples>(tuples))’
這是因為我在同一表達式中使用了兩個長度不同的包( I
和Tuples
)。
我想不出另一種編寫此函數的方法,該方法不會在同一表達式中使用兩個包。
實現tuple_map
的最佳方法是什么?
如果我了解您要正確執行的操作,則此代碼似乎可以解決Visual Studio 2013(2013年11月CTP)的問題:
#include <iostream>
#include <tuple>
#include <utility>
using namespace std;
// index_sequence implementation since VS2013 doesn't have it yet
template <size_t... Ints> class index_sequence {
public:
static size_t size() { return sizeof...(Ints); }
};
template <size_t Start, typename Indices, size_t End>
struct make_index_sequence_impl;
template <size_t Start, size_t... Indices, size_t End>
struct make_index_sequence_impl<Start, index_sequence<Indices...>, End> {
typedef typename make_index_sequence_impl<
Start + 1, index_sequence<Indices..., Start>, End>::type type;
};
template <size_t End, size_t... Indices>
struct make_index_sequence_impl<End, index_sequence<Indices...>, End> {
typedef index_sequence<Indices...> type;
};
template <size_t N>
using make_index_sequence =
typename make_index_sequence_impl<0, index_sequence<>, N>::type;
// The code that actually implements tuple_map
template <size_t I, typename F, typename... Tuples>
auto tuple_zip_invoke(F f, const Tuples &... ts) {
return f(get<I>(ts)...);
}
template <typename F, size_t... Is, typename... Tuples>
auto tuple_map_impl(F f, index_sequence<Is...>, const Tuples &... ts) {
return make_tuple(tuple_zip_invoke<Is>(f, ts...)...);
}
template <typename F, typename Tuple, typename... Tuples>
auto tuple_map(F f, const Tuple &t, const Tuples &... ts) {
return tuple_map_impl(f, make_index_sequence<tuple_size<Tuple>::value>(), t,
ts...);
}
int sum(int a, int b, int c) { return a + b + c; }
int main() {
auto res =
tuple_map(sum, make_tuple(1, 4), make_tuple(2, 5), make_tuple(3, 6));
cout << "(" << get<0>(res) << ", " << get<1>(res) << ")\n";
return 0;
}
輸出為:
(6, 15)
我可能會通過考慮映射和類別來解決此問題。 使用現有的tuple_map
,嘗試以下操作:
template <typename ...Tuple, typename F>
auto tuple_map(Tuple && tuple, F f)
{
return std::tuple_cat(tuple_map(std::forward<Tuple>(tuple), f)...);
}
您可以像這樣使用遞歸和std::tuple_cat()
:
template <class Function, class Tuple, size_t... I>
auto tuple_map_impl(Function f, Tuple&& t, std::index_sequence<I...>)
{
return std::make_tuple(f(std::get<I>(std::forward<Tuple>(t)))...);
}
template <class F, class Tuple, class... Tuples>
auto tuple_map(F f, Tuple&& t, Tuples&&... tuples)
{
return std::tuple_cat(tuple_map_impl(f, std::forward<Tuple>(t), std::make_index_sequence<std::tuple_size<std::decay_t<Tuple>>::value>{}),
tuple_map(f, tuples...));
}
template <class F>
auto tuple_map(F) { return std::make_tuple(); }
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.