带有函子的自动类型推理不起作用

Auto type inference with functor does not work

本文关键字:类型 推理 不起作用      更新时间:2023-10-16

可能重复:
std::绑定绑定函数

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

问题是std::bind对待"绑定表达式"(如applyWithFoo0)与其他类型不同。它不使用applyWithFoo0作为参数来调用foo1,而是尝试调用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;
}

这实际上是编译和工作的,因为bind并没有像从绑定表达式#2和#3中预期的那样将函子传递两次,而是实际计算传递的绑定表达式,并且将其结果用作函数参数两次。在这里,它是故意的。但在您的案例中,您意外地被这种行为绊倒了,因为您实际上希望bind将函子本身传递给函数,而不是其求值值。将函子封装为函数<>对象显然是一个变通办法。

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

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

其中noeval告诉bind不要计算表达式,而是直接将其传递给函数。但也许另一种方法——明确地告诉bind将函子的结果传递给函数——会是更好的设计:

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

但我想,现在已经太晚了。。。

我的猜测是,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);
}