web-dev-qa-db-ja.com

std :: bindの反対、与えられたパラメーターに対して異なる関数を渡す

ほぼ同じシグネチャを持ついくつかの関数があります(実際のコードよりはるかに短くなっています)。

int hello(A a, B b, C c, int n);
int there(A a, B b, C c, int n);
int how(A a, B b, C c, int n);
int are(A a, B b, C c, int n);
...

等々。次に、呼び出し中に、コードはパラメーターを1回作成してから、nを除くすべての関数に同じオブジェクトを渡します。

A a; B b; C c;
hello(a, b, c, 240);
there(a, b, c, 33);
how(a, b, c, 54);
are(a, b, c, 67);

私が達成したいのは、関数を交換したいということを除いて、std::bindが通常使用される方法に似たものです。例えば:

auto uber_func = std::something_stack_overflow_recommends(..., a, b, c)
uber_func(hello, 240);
uber_func(there, 33);
uber_func(how, 54);
uber_func(are, 67);

std::bindのドキュメントから、これが可能かどうかは不明でした。何か提案はありますか?

13
jeanluc

Lambdaを使用できます。これにより、std::bindは使いやすくなり、ほとんど廃止されました。

  auto uber_func = [&](std::function<int(A, B, C, int)> f, int n) {
    return f(a, b, c, n);
  };

  uber_func(hello, 240);
  uber_func(there, 33);
  uber_func(how, 54);
  uber_func(are, 67);

最初のソリューションは、すべての機能が同じ既知のインターフェースを持つことを強制します。必要に応じて、さまざまなタイプの関数もサポートするように一般化できます。

  auto uber_func = [&](auto f, int n) {
    return f(a, b, c, n);
  };

2番目のソリューションはより一般的で、最初のソリューションのパフォーマンスオーバーヘッドを回避します。小さな欠点:C++ 14コンパイラが必要ですが、最初のコンパイラはすべてのC++ 11コンパイラで動作するはずです。それが問題なければ、私は最初の解決策よりも2番目の解決策を好むでしょう。

あなたがstd::bindでそれを行う方法について質問したのに気づきましたが、私はそれに答えませんでした。ただし、C++ 11以降、Lambdasはstd::bindを大幅に置き換えました。 C++ 14以降、さらに改善が加えられたため、さらに明確になりました。 C++ 98との互換性が厳密な要件でない限り、私は Lambdasを優先してstd::bindを避ける をお勧めします。

11
Philipp Claßen

最後以外のすべてのパラメーターを使用してオブジェクトを作成できます。

template<typename A, typename B, typename C>
struct uber
{
   A a;
   B b;
   C c;

   uber(A a, B b, C c) : a(a), b(b), c(c) {}

   template<typename F> 
   auto operator()(F f, int n) { f(a,b,c,n); }
};

次に、テンプレート化された呼び出し演算子を使用して、個々の関数を呼び出します。

A a; B b; C c;
auto uber_func = uber{a,b,c};
uber_func(hello, 240);
uber_func(there, 33);
uber_func(how, 54);
uber_func(are, 67);
3
cigien