首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >函子自动类型推理不起作用

函子自动类型推理不起作用
EN

Stack Overflow用户
提问于 2012-07-24 13:06:00
回答 2查看 270关注 0票数 1

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

代码语言:javascript
复制
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

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2012-07-25 08:41:10

问题是,std::bind对待“绑定表达式”(与applyWithFoo0一样)与其他类型不同。它不使用foo1作为参数调用applyWithFoo0,而是尝试调用applyWithFoo0并将其返回值传递给foo1。但是applyWithFoo0不返回任何可转换为std::function<void(int)>的东西。像这样处理“绑定表达式”的目的是使它们易于组合。在大多数情况下,您可能不希望bind表达式作为函数参数传递,而只希望它们的结果。如果将绑定表达式显式包装到function<>对象中,则function<>对象将直接传递给foo1,因为它不是“绑定表达式”,因此不是std::bind专门处理的。

请考虑以下示例:

代码语言:javascript
复制
#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。在这里,这是故意的。但是在您的例子中,您意外地被这种行为绊倒了,因为您实际上希望绑定将函子本身传递给函数,而不是它的计算值。将函子包装到function<>对象显然是一种解决方法。

在我看来,这个设计决策有点尴尬,因为它引入了一个不规则性,人们必须知道如何正确地使用bind。也许,我们将来还会有更多令人满意的工作

代码语言:javascript
复制
auto applyFoo1 = bind( foo1, _1, noeval(applyWithFoo0) );

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

代码语言:javascript
复制
auto mul_by_8 = bind( twice, eval(mul_by_4) );

但我想现在已经太晚了。

票数 1
EN

Stack Overflow用户

发布于 2012-07-24 15:11:18

我的猜测是std::bind周围的括号使解析器认为您在声明名为applyWithFoo0和applyFoo1的函数。

bind::bind返回一个函子,它的类型应该是auto能够检测到的。

试试这个:

代码语言:javascript
复制
 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);
}
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/11631519

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档