为什么我不能在bind中使用mem_fn Functor?

时间:2017-07-26 15:18:47

标签: c++ c++11 bind functor mem-fun

我想将mem_fn参数传递给bind,但编译器似乎不允许它。

例如,这样可以正常工作:

accumulate(cbegin(foos), cend(foos), 0, bind(plus<int>(), placeholders::_1, bind(&foo::r, placeholders::_2)));

但是当我尝试使用mem_fn仿函数时,我会得到一页错误:

accumulate(cbegin(foos), cend(foos), 0, bind(plus<int>(), placeholders::_1, mem_fn(&foo::r)));
  

/ usr / include / c ++ / 6 / bits / stl_numeric.h:实例化'_Tp std :: accumulate(_InputIterator,_InputIterator,_Tp,_BinaryOperation)[with _InputIterator = __gnu_cxx :: __ normal_iterator&gt ;; _Tp = int; _BinaryOperation = std :: _ Bind(std :: _ Placeholder&lt; 1&gt;,std :: _ Mem_fn)&gt;]':
  prog.cpp:20:102:从这里要求
  /usr/include/c++/6/bits/stl_numeric.h:154:22:错误:无法调用'(std :: _ Bind(std :: _ Placeholder&lt; 1&gt;,std :: _ Mem_fn)&gt;)( int&amp;,foo * const&amp;)'

2 个答案:

答案 0 :(得分:2)

嗯,显然,第二个例子没有提到placeholders::_2。当accumulate使用两个参数调用仿函数时,第二个参数将被忽略,并且您的代码正在尝试添加intmem_fn返回的内部类的实例。

我建议您放弃所有这些bind游戏,并使用lambda:

accumulate(cbegin(foos), cend(foos), 0, 
    [](int val, foo* f) { return val + f->r(); });

更清楚这里发生了什么。

答案 1 :(得分:0)

要理解这一点,请考虑一下如果只是将文字传递给bind的3 rd 参数,意味着什么。例如,如果你做了:

accumulate(cbegin(foos), cend(foos), 0, bind(plus<int>(), placeholders::_1, 13))

结果应为size(foos) * 13,因为plus会在每次迭代时使用13作为加数。

accumulate(cbegin(foos), cend(foos), 0, bind(plus<int>(), placeholders::_1, mem_fn(&foo::r)))

无法编译,因为它试图将mem_fn(&foo::r)的结果作为加号传递给plus。由于无法将其转换为int plus,因此无法接受。但即使它可以转换为int,这不是你想要的,你想要取2 nd 参数并在其上调用foo::r,传递结果plus。因此,我们知道我们需要看到placeholders::_2在语句中的某处使用,传达了2 nd 参数,用于调用它的r方法。

我们需要绑定placeholders::_2绑定到一个仿函数,该仿函数将在其参数上调用r方法。绑定当然需要bind,但实际上需要bind can take a method as it's 1st argument

也就是说,工作代码中的bind(&foo::r, placeholders::_2)语句在非嵌套形式中没有任何意义;仿函数甚至不带2个参数! 实际上有special rules for handling a bind nested within another bind,因此他们可以共享外部bind的占位符,以免无法将绑定参数传递给嵌套表达式:

  

如果存储的参数arg的类型为T std::is_bind_expression<T>::value == true(例如,另一个bind表达式直接传递给bind的初始调用),那么bind执行函数组合:不是传递bind子表达式将返回的函数对象,而是急切地调用子表达式,并将其返回值传递给外部可调用对象。如果bind子表达式包含任何占位符参数,则它们将与外部bind共享。

在此表达式中使用mem_fn的唯一方法是将结果传递给bind以传达placeholders::_2bind(mem_fn(&foo::r), placeholders::_2)这有效,但是简单的bind(&foo::r, placeholders::_2)就足够了。因此,生成此仿函数的最佳方法是使用您提供的语句:

accumulate(cbegin(foos), cend(foos), 0, bind(plus<int>(), placeholders::_1, bind(&foo::r, placeholders::_2)))

或者使用lambda:

accumulate(cbegin(foos), cend(foos), 0, [](const int augend, const auto& addend) { return augend + addend.r(); } )