如何将变函数fn<S,...Args>泛化为fn<S0,...Args0,S1,...Args1,...,SN,...ArgsN&gt。

问题描述 投票:2回答:1

假设有变函数 template<typename... Args> foo(const S& s, Args... args).

struct S {};

template<typename... Args>
void foo(const S& s, Args... args);

void check_foo()
{
  S s0{};
  S s1{};
  char  a0 = 0;
  short a1 = 1;
  int   a2 = 2;
  foo(s0, a0); // OK
  foo(s0, a0, a1); // OK
  foo(s1, a1, a2); // OK
}

有沒有辦法寫功能 bar(const S& s0, Args0...args0, const S& s1, Args1...args1, ..., const S& sN, ArgsN...argsN) 扩充为 foo(s0, args0...); foo(s1, args1...); ...; foo(sN, argsN...);?

我已经试过了(没有成功)。

#include <type_traits>
template<typename... Args,
  typename = std::enable_if_t<
    !(... || std::is_same_v<S, Args>)
  >
>
void bar(const S& s, Args... args)
{
  foo(s, args...);
}

template<typename... Args0, typename... Args1>
void bar(
  const S& s0, Args0... args0,
  const S& s1, Args1... args1)
{
  bar(s0, args0...); // ??? call to foo
  bar(s1, args1...); // ??? recursive to bar or to foo
}

void check_bar()
{
  S s0{};
  S s1{};
  char  a0 = 0;
  short a1 = 1;
  int   a2 = 2;
  bar(s0, a0); // OK
  bar(s1, a1, a2); // OK

  bar(s0, a0,
      s0, a0, a1,
      s1, a1, a2); // fail
}

如果我理解正确的话,编译器(clang 9.0.0)总是将Args0扩展为空列表,匹配失败。

c++ variadic-functions pack-expansion
1个回答
3
投票

类似于这样的思路。

template <typename... Args>
void bar(const S& s, Args... args);

template<typename Tuple, std::size_t... Is>
void call_foo(const Tuple& t, std::index_sequence<Is...>) {
    foo(std::get<Is>(t)...);
}

template<size_t nextS, typename Tuple, std::size_t... Is>
void call_bar(const Tuple& t, std::index_sequence<Is...>) {
    bar(std::get<Is + nextS>(t)...);
}

template <typename... Args, std::size_t... Is>
void bar_helper(const S& s, std::index_sequence<Is...>, Args... args) {
    constexpr size_t N = sizeof...(Is);
    if constexpr (N == 0) {
      foo(s);
    }
    if constexpr (N > 0) {
      constexpr size_t nextS = 1 + std::min<std::size_t>(
          {(std::is_same_v<S, std::decay_t<Args>> ? Is : N) ...});
      auto t = std::forward_as_tuple(s, args...);
      call_foo(t, std::make_index_sequence<nextS>{});
      if constexpr (nextS <= N) {
         call_bar<nextS>(t, std::make_index_sequence<N - nextS + 1>{});
      }
   }
}

template <typename... Args>
void bar(const S& s, Args... args) {
  bar_helper(s, std::make_index_sequence<sizeof...(Args)>{}, args...);
}

演示

© www.soinside.com 2019 - 2024. All rights reserved.