1

重複の可能性:
std::bindバインドされた関数

void foo0(int val) { std::cout << "val " << val << "\n"; }
void foo1(int val, std::function<void (int)> ftor) { ftor(val); }
void foo2(int val, std::function<void (int)> ftor) { ftor(val); }

int main(int argc, char* argv[]) {
    auto                applyWithFoo0       ( std::bind(foo0,     std::placeholders::_1) );
    //std::function<void (int)> applyWithFoo0       ( std::bind(foo0,     std::placeholders::_1) ); // use this instead to make compile
    auto                applyFoo1       (     std::bind(foo1, std::placeholders::_1, applyWithFoo0) );
    foo2(123, applyFoo1);
}

上記のサンプルはコンパイルされず、次のような複数のエラーが発生しますError 1 error C2780: '_Ret std::tr1::_Callable_fun<_Ty,_Indirect>::_ApplyX(_Arg0 &&,_Arg1 &&,_Arg2 &&,_Arg3 &&,_Arg4 &&,_Arg5 &&,_Arg6 &&,_Arg7 &&,_Arg8 &&,_Arg9 &&) const' : expects 10 arguments - 2 provided
コメント付きの行を明示的な型で使用すると、コンパイルされます。によって推測されたタイプautoが正しくないようです。autoこの場合の問題は何ですか?
プラットフォーム:MSVC 10 SP 1、GCC 4.6.1

4

2 に答える 2

1

問題は、std::bind「バインド式」( などapplyWithFoo0) を他のタイプとは異なる方法で扱うことです。パラメータとしてfoo1 を呼び出す代わりに、呼び出してその戻り値を foo1 に渡そapplyWithFoo0うとします。applyWithFoo0しかしapplyWithFoo0、 に変換できるものは何も返しませんstd::function<void(int)>。このように「バインド式」を処理する意図は、それらを簡単に構成できるようにすることです。ほとんどの場合、バインド式を関数パラメーターとして渡すのではなく、その結果のみを渡す必要があります。function<>バインド式をオブジェクトに明示的にラップする場合、オブジェクトは「バインド式」ではないfunction<>ため foo1 に直接渡されるだけであり、したがって によって特別に処理されることはありません。std::bind

次の例を検討してください。

#include <iostream>
#include <functional>

int twice(int x) { return x*2; }

int main()
{
  using namespace std;
  using namespace std::placeholders;
  auto mul_by_2 = bind(twice,_1);
  auto mul_by_4 = bind(twice,mul_by_2); // #2
  auto mul_by_8 = bind(twice,mul_by_4); // #3
  cout << mul_by_8(1) << endl;
}

バインド式 #2 と #3 から期待されるようにファンクターを Twice に渡す代わりに、bind は実際に渡されたバインド式を評価し、その結果を Twice の関数パラメーターとして使用するため、これは実際にコンパイルして機能します。ここでは、それは意図的です。しかし、あなたのケースでは、bind が評価された値の代わりにファンクター自体を関数に渡すことを実際に望んでいるため、偶然この動作につまずきました。ファンクターを function<> オブジェクトにラップすることは、明らかにその回避策です。

私の意見では、この設計上の決定は、バインドを正しく使用できるようにするために知っておく必要がある不規則性を導入するため、少しぎこちないものです。たぶん、私たちは将来、次のような別のより満足のいく仕事を手に入れるでしょう

auto applyFoo1 = bind( foo1, _1, noeval(applyWithFoo0) );

wherenoevalは、式を評価するのではなく、それを直接関数に渡すように bind に指示します。しかし、逆に、バインドにファンクターの結果を関数に渡すように明示的に指示する方が、より良い設計になる可能性があります。

auto mul_by_8 = bind( twice, eval(mul_by_4) );

しかし、今では手遅れだと思います...

于 2012-07-25T08:41:10.053 に答える
0

私の推測では、std :: bindの括弧は、applyWithFoo0およびapplyFoo1という名前の関数を宣言しているとパーサーに思わせます。

std :: bindは、autoが検出できるタイプのファンクターを返します。

これを試して:

 int main(int argc, char* argv[]) {
    auto                applyWithFoo0  =     std::bind(foo0,     std::placeholders::_1);
    //std::function<void (int)> applyWithFoo0        std::bind(foo0,     std::placeholders::_1) ); // use this instead to make compile
    auto                applyFoo1   =    std::bind(foo1, std::placeholders::_1, applyWithFoo0);
    foo2(123, applyFoo1);
}
于 2012-07-24T15:11:18.663 に答える