使用仿函数的自动类型推断不起作用

时间:2012-07-24 13:06:00

标签: c++ c++11 bind std stdbind

  

可能重复:
  std::bind a bound function

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

2 个答案:

答案 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);
}