タプルを「アンパック」して、一致する関数ポインターを呼び出す 質問する

タプルを「アンパック」して、一致する関数ポインターを呼び出す 質問する

さまざまな数の値を格納しようとしていますstd::tuple。これらの値は、後に格納された型に一致する関数ポインターの呼び出しの引数として使用されます。

私が解決に苦労している問題を示す簡略化された例を作成しました。

#include <iostream>
#include <tuple>

void f(int a, double b, void* c) {
  std::cout << a << ":" << b << ":" << c << std::endl;
}

template <typename ...Args>
struct save_it_for_later {
  std::tuple<Args...> params;
  void (*func)(Args...);

  void delayed_dispatch() {
     // How can I "unpack" params to call func?
     func(std::get<0>(params), std::get<1>(params), std::get<2>(params));
     // But I *really* don't want to write 20 versions of dispatch so I'd rather 
     // write something like:
     func(params...); // Not legal
  }
};

int main() {
  int a=666;
  double b = -1.234;
  void *c = NULL;

  save_it_for_later<int,double,void*> saved = {
                                 std::tuple<int,double,void*>(a,b,c), f};
  saved.delayed_dispatch();
}

std::tuple通常、可変長テンプレートを含む問題の場合は、template <typename Head, typename ...Tail>すべての型を 1 つずつ再帰的に評価するような別のテンプレートを作成しますが、関数呼び出しをディスパッチするためにそれを実行する方法がわかりません。

これの本当の動機はもう少し複雑で、とにかくほとんどは単なる学習演習です。別のインターフェースからの契約によってタプルが渡されるので変更できないが、関数呼び出しに展開したいという欲求は私のものであると想定できます。これにより、std::bind根本的な問題を回避するための安価な方法として を使用することは除外されます。

を使用して呼び出しをディスパッチするクリーンな方法std::tuple、または任意の将来の時点までいくつかの値と関数ポインターを保存/転送するという同じ最終結果を達成するより良い代替方法は何ですか?

ベストアンサー1

数値のパラメータパックを構築し、それを展開する必要がある

template<int ...>
struct seq { };

template<int N, int ...S>
struct gens : gens<N-1, N-1, S...> { };

template<int ...S>
struct gens<0, S...> {
  typedef seq<S...> type;
};


// ...
  void delayed_dispatch() {
     callFunc(typename gens<sizeof...(Args)>::type());
  }

  template<int ...S>
  void callFunc(seq<S...>) {
     func(std::get<S>(params) ...);
  }
// ...

おすすめ記事