C++ 如何实现可变元组映射操作?

C++ 如何实现可变元组映射操作?,c++,tuples,variadic-templates,c++14,C++,Tuples,Variadic Templates,C++14,我想实现一个函数,在给定一个函数的情况下,将一个元组的可变列表映射到另一个元组 它将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_

我想实现一个函数,在给定一个函数的情况下,将一个元组的可变列表映射到另一个元组

它将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\u map
,具有以下签名:

template<class Tuple1, class... Tuples2, class Function>
auto tuple_map(Tuple1&& tuple1, Tuples&&... tuples, Function f);
编译器错误:

error: mismatched argument pack lengths while expanding ‘get<I>(forward<Tuples>(tuples))’
错误:展开“get(forward(tuples))”时参数包长度不匹配
这是因为我在同一个表达式中使用了两个长度不同的包(
I
Tuples

我想不出另外一种方法来编写这个函数,它不会在同一个表达式中使用两个包


实现元组映射的最佳方法是什么?

我可以通过分解映射和catting来解决这个问题。使用现有的
元组映射
,尝试以下操作:

template <typename ...Tuple, typename F>
auto tuple_map(Tuple && tuple, F f)
{
    return std::tuple_cat(tuple_map(std::forward<Tuple>(tuple), f)...);
}
模板
自动元组映射(元组和元组,F)
{
返回std::tuple_cat(tuple_map(std::forward(tuple),f)…);
}

我可以通过分解映射和散射来解决这个问题。使用现有的
元组映射
,尝试以下操作:

template <typename ...Tuple, typename F>
auto tuple_map(Tuple && tuple, F f)
{
    return std::tuple_cat(tuple_map(std::forward<Tuple>(tuple), f)...);
}
模板
自动元组映射(元组和元组,F)
{
返回std::tuple_cat(tuple_map(std::forward(tuple),f)…);
}

您可以像这样使用递归和
std::tuple\u 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(); }
模板
自动元组映射实现(函数f、元组和t、std::索引序列)
{
返回std::make_tuple(f(std::get(std::forward(t)))…);
}
模板
自动元组映射(F、F、元组和t、元组和…元组)
{
返回std::tuple_cat(tuple_map_impl(f,std::forward(t),std::make_index_sequence{}),
元组映射(f,元组…);
}
模板
自动元组映射(F){return std::make_tuple();}

您可以像这样使用递归和
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(); }
模板
自动元组映射实现(函数f、元组和t、std::索引序列)
{
返回std::make_tuple(f(std::get(std::forward(t)))…);
}
模板
自动元组映射(F、F、元组和t、元组和…元组)
{
返回std::tuple_cat(tuple_map_impl(f,std::forward(t),std::make_index_sequence{}),
元组映射(f,元组…);
}
模板
自动元组映射(F){return std::make_tuple();}

如果我理解您正试图正确执行的操作,则此代码似乎在Visual Studio 2013(2013年11月CTP)中起到了作用:


如果我理解您正试图正确执行的操作,那么这段代码似乎在Visual Studio 2013(2013年11月CTP)中起到了作用:


你能先给出一个完整的规范,说明函数应该做什么吗?根据一个公认的答案,实际上你想要一个函数,它将一个
N
-元函数f应用于从
N
元组列表(每个元组的大小
M
)中提取的元素列表并根据这些应用程序的结果创建一个新的
M
元素元组。感谢您的关注!你能先给出一个完整的规范,说明函数应该做什么吗?根据一个公认的答案,实际上你想要一个函数,它将一个
N
-元函数f应用于从
N
元组列表(每个元组的大小
M
)中提取的元素列表并根据这些应用程序的结果创建一个新的
M
元素元组。感谢您的关注!
#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)