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,applyWithFoo0而是尝试调用applyWithFoo0并将其返回值传递给 foo1。但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 那样将函子传递给两次,bind 实际上会计算传递的绑定表达式并将其结果用作函数参数两次。在这里,这是故意的。但是在您的情况下,您偶然绊倒了这种行为,因为您实际上希望 bind 将仿函数本身而不是其评估值传递给函数。将仿函数包装到 function<> 对象中显然是一种解决方法。

在我看来,这个设计决定有点尴尬,因为它引入了人们必须知道才能正确使用绑定的不规则性。也许,我们将来会得到另一个更令人满意的工作,比如

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

wherenoeval告诉 bind 不要计算表达式,而是将其传递给函数。但也许反过来——明确告诉 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 回答