Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unpack ts... to t0.a(), t0.b(), t1.a(), t1.b(),

I want to call one variadic function from another variadic function in the following manner:

template <typename ...Ts>
void f(Ts const & ...) { /* ... */ }

template <typename ...Args>
void g(Args const & ...args)
{
  // shall call f(arg0.a(), arg0.b(), arg1.a(), arg1.b(), ...)
}

I have done it the following way:

struct sentinel_t { };

template <typename Arg, typename ...Args>
void g_impl(Arg const & arg, Args const & ...args)
{
  g_impl(args..., arg.a(), arg.b());
}

template <typename ...Ts>
void g_impl(sentinel_t , Ts const & ...ts)
{
  f(ts...);
}

template <typename ...Args>
void g(Args const & ...args)
{
  g_impl(args..., sentinel_t{});
}

Is there another/better way to implement this pattern?

like image 554
MadScientist Avatar asked May 29 '15 12:05

MadScientist


2 Answers

template <class... Args> void g(Args const &... args) {
  impl::apply([](auto const &... p) { f(p...); },
              std::tuple_cat(std::forward_as_tuple(args.a(), args.b())...));
}

until std::apply will be standardized you can make your own pretty simple with c++14 (taken from the referenced paper):

namespace impl {
template <typename F, typename Tuple, size_t... I>
decltype(auto) apply_impl(F &&f, Tuple &&t, std::index_sequence<I...>) {
  return std::forward<F>(f)(std::get<I>(std::forward<Tuple>(t))...);
}
template <typename F, typename Tuple> decltype(auto) apply(F &&f, Tuple &&t) {
  using Indices =
      std::make_index_sequence<std::tuple_size<std::decay_t<Tuple>>::value>;
  return apply_impl(std::forward<F>(f), std::forward<Tuple>(t), Indices{});
}
}
like image 75
bolov Avatar answered Nov 05 '22 20:11

bolov


You may do

namespace detail
{

    // dispatcher
    template <typename T>
    decltype(auto) call_a_b(std::integral_constant<std::size_t, 0u>, const T& arg) {return arg.a();}

    // dispatcher
    template <typename T>
    decltype(auto) call_a_b(std::integral_constant<std::size_t, 1u>, const T& arg) {return arg.b();}

    template <std::size_t... Is, typename Tuple>
    void call_f_a_b(std::index_sequence<Is...>, const Tuple& tuple)
    {
        f(call_a_b(std::integral_constant<std::size_t, Is % 2>{}, std::get<Is / 2>(tuple))...);
    }

}

template <typename...Ts>
void g(const Ts&... args)
{
    return detail::call_f_a_b(std::make_index_sequence<2 * sizeof...(Ts)>{}, std::tie(args...));
    // call f(arg0.a(), arg0.b(), arg1.a(), arg1.b(), ...)
}

Live Demo

like image 4
Jarod42 Avatar answered Nov 05 '22 19:11

Jarod42