簡體   English   中英

如何實現可變參數tuple_map操作?

[英]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))’

這是因為我在同一表達式中使用了兩個長度不同的包( ITuples )。

我想不出另一種編寫此函數的方法,該方法不會在同一表達式中使用兩個包。

實現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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM