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
答案 0 :(得分:1)
问题是std::bind
对待“绑定表达式”(与您的applyWithFoo0
)不同于其他类型。它不是以applyWithFoo0
作为参数调用foo1,而是尝试调用applyWithFoo0
并将其返回值传递给foo1。但applyWithFoo0
不会返回任何可转换为std::function<void(int)>
的内容。像这样处理“绑定表达式”的目的是使它们易于组合。在大多数情况下,您可能不希望将bind表达式作为函数参数传递,而只传递其结果。如果将绑定表达式显式地包装到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将functor本身传递给函数而不是它的评估值。将仿函数包装成函数&lt;&gt;对象显然是一种解决方法。
在我看来,这个设计决定有点尴尬,因为它引入了人们必须知道能够正确使用绑定的不规则性。也许,我们将来会得到另一个更令人满意的工作,比如
auto applyFoo1 = bind( foo1, _1, noeval(applyWithFoo0) );
其中noeval
告诉bind不要评估表达式,而是将它传递给函数。但也许反过来 - 明确告诉bind将函数的结果传递给函数 - 本来是一个更好的设计:
auto mul_by_8 = bind( twice, eval(mul_by_4) );
但我猜,现在为时已晚......
答案 1 :(得分: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);
}