2017-07-26 77 views
0

我想通过一个mem_fn参数bind但编译器似乎不允许它。为什么我不能在绑定中使用mem_fn Functor?

例如这工作正常:

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: In instantiation of ‘_Tp std::accumulate(_InputIterator, _InputIterator, _Tp, _BinaryOperation) [with _InputIterator = __gnu_cxx::__normal_iterator >; _Tp = int; _BinaryOperation = std::_Bind(std::_Placeholder<1>, std::_Mem_fn)>]’:
prog.cpp:20:102: required from here
/usr/include/c++/6/bits/stl_numeric.h:154:22: error: no match for call to ‘(std::_Bind(std::_Placeholder<1>, std::_Mem_fn)>) (int&, foo* const&)’

+0

你是第一人,我看到使用'bind'的特殊处理嵌套绑定表达式而不知道它。 –

+0

mem_fn已弃用,请勿使用它。 –

+1

@ n.m。它是?我知道它内部的typedefs将在C++ 17中,但我没有看到有关'mem_fn'本身的任何内容被弃用。 – NathanOliver

回答

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))) 

不能编译,因为它试图为被加数plus传递的mem_fn(&foo::r)结果。既然不能转换成intplus不能接受。但即使它可以转换为int,但这不是您要查找的内容,您需要参数并致电foo::r,并将结果传递给plus。因此我们知道我们需要看到,在该陈述中的某处使用placeholders::_2,传达了其调用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的占位符,恐怕没有的方式来传达绑定参数嵌套表达式:

If the stored argument arg is of type T for which std::is_bind_expression<T>::value == true (for example, another bind expression was passed directly into the initial call to bind), then bind performs function composition: instead of passing the function object that the bind subexpression would return, the subexpression is invoked eagerly, and its return value is passed to the outer invokable object. If the bind subexpression has any placeholder arguments, they are shared with the outer 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))) 

,或者通过使用拉姆达:

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

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

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

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

更清楚什么是怎么回事。

相关问题