C++17 多参数包扩展

Ran*_*its 3 c++ templates variadic-templates c++17

我试图将函数映射f到 tuplest0t1以返回 tuple std::tuple<f(std::get<0>(t0),std:get<0>(t1),...),f(std::get<1>(t0),std::get<1>(t1),...),...)。我有一个使用car,工作的版本cdrcons但我正在尝试使用std::index_sequence.

代码:

// Helper
template<typename T>
using make_tuple_index = std::make_index_sequence<std::tuple_size<T>::value>;

// Implementation
template<typename F, typename... Ts, std::size_t... Is>
auto mapx_n_impl(const F& f, std::index_sequence<Is...>, const Ts&... t)
{ return std::make_tuple(f(std::get<Is>(t...))...); }

// Interface
template<typename T,
         typename F,
         typename Indices = make_tuple_index<T>>
auto map(const T& t, const F& f)
{ return mapx_impl(t, f, Indices{}); }

// Test
auto tup1 = std::make_tuple(1.0, 2.0, 3.0);
auto tup2 = std::make_tuple(0.0, 1.0, 2.0);
auto r = mapx_n([](auto x, auto y) { return x - y; }, tup1, tup2);
Run Code Online (Sandbox Code Playgroud)

问题在于扩展实现返回语句中的参数包。t我需要它在“内”循环和Is“外”循环中扩展。扩张是如何控制的?而且,我该如何修改我的退货单?

更新:

根据@Yakk的回复和@max66的进一步说明,我尽可能地简化了我的代码。当前版本集成了 @Yakk 答案中的参数包扩展助手版本,并将 get_element 调用分解为 lambda。

// invoke_with_pack
template<std::size_t... Is, typename F>
auto invoke_with_pack(std::index_sequence<Is...>, F&& function)
{ return function(std::integral_constant<std::size_t, Is>{}...); }

// nth
template<natural N, typename... Ts>
using nth = typename std::tuple_element<N, std::tuple<Ts...>>::type;

// make_tuple_index -- Helper template for computing indices
// corresponding to a tuple.
template<typename T>
using make_tuple_index = std::make_index_sequence<std::tuple_size<T>::value>;

// map_n -- Map <function> over <tuples> t0,t1,...
template<typename F,
         typename... Ts,
         typename Indices = make_tuple_index<nth<0,Ts...>>>
auto map_n(F&& function, Ts&... tuples)
{
    auto get_element = [&](auto I) { return function(std::get<I>(tuples)...); };
    return invoke_with_pack(Indices{}, [&](auto... Is) {
            return std::make_tuple(get_element(Is)...);
        });
}
Run Code Online (Sandbox Code Playgroud)

现在来弄清楚如何使用索引而不是 car、cdr 和 cons 来实现 Fold_left 和 Fold_right。

Yak*_*ont 6

从这个开始:

namespace utility {
  template<std::size_t...Is>
  auto index_over( std::index_sequence<Is...> ) {
    return [](auto&& f)->decltype(auto) {
      return decltype(f)(f)( std::integral_constant<std::size_t, Is>{}... );
    };
  }
  template<std::size_t N>
  auto index_upto( std::integral_constant<std::size_t, N> ={} ) {
    return index_over( std::make_index_sequence<N>{} );
  }
}
Run Code Online (Sandbox Code Playgroud)

这让我们避免了仅仅为了扩展一些参数包而编写一大堆函数。 index_upto<7>()([](auto...Is){ /* here */ })为您提供一个上下文,其中包含一堆编译时积分常量 0 到 6。

template<class F, class T0, class...Tuples>
auto map_over_tuples( F&& f, T0&... t0, Tuples&&... tuples ) {
  using tuple_size = typename std::tuple_size< std::decay_t<T0> >::type;

  auto get_element = [&](auto I){
    return f(std::get<I>(std::forward<T0>(t0)), std::get<I>(std::forward<Tuples>(tuples)...));
  };
  return index_upto<tuple_size{}>()([&](auto...Is){
    return std::make_tuple( get_element(Is)... );
  });
}
Run Code Online (Sandbox Code Playgroud)

在某些编译器中,I必须将 of 的使用替换为decltype(I)::valuein get_element