I wanted to pass a mem_fn
argument to bind
but the compiler doesn't seem to allow it.
For example this works fine:
accumulate(cbegin(foos), cend(foos), 0, bind(plus<int>(), placeholders::_1, bind(&foo::r, placeholders::_2)));
But when I try to use the mem_fn
functor I get about a page of errors:
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&)’
To understand this, think about what it would mean if you just passed a literal to
bind
's 3rd argument. For Example if you had done:The result would have been
size(foos) * 13
, becauseplus
would have used13
as it's addend on each iteration.Won't compile because it's attempting to pass the result of
mem_fn(&foo::r)
as the addend toplus
. Since that can't be converted to anint
plus
can't accept that. But even if it could be converted to anint
, that's not what you're looking for, you want to take the 2nd argument and callfoo::r
on it, passing the result toplus
. Thus we know we need to see,placeholders::_2
used somewhere in the statement, conveying the 2nd argument for the calling of it'sr
method.We need to bind
placeholders::_2
to be bound to a functor which will call ther
method on it's parameter. The binding will of course requirebind
, but actuallybind
can take a method as it's 1st argument.That said, the
bind(&foo::r, placeholders::_2)
statement from your working code doesn't make any sense in non-nested form; that functor doesn't even take 2 parameters! c++ actually has special rules for handling abind
nested within anotherbind
, so that they can share the outerbind
's placeholders, lest there be no way to convey a bound argument to a nested expression:The only way to use
mem_fn
in this expression would be to pass it it's result tobind
for the conveying ofplaceholders::_2
:bind(mem_fn(&foo::r), placeholders::_2)
This works, but is an unnecessary step when the simplebind(&foo::r, placeholders::_2)
will suffice. Thus the best way to generate this functor is either with your proffered statement:Or by using a lambda: