Why use mem_fn?

Jonathan. picture Jonathan. · May 16, 2016 · Viewed 9.7k times · Source

I'm confused as to why std::mem_fn is needed.

I have a function that takes in any callable (lambda, function pointer, etc),and binds it to an argument.

Eg:

template<class T>
void Class::DoBinding(T callable) {
  m_callable = std::bind(callable, _1, 4);
}
//somewhere else
Item item;
m_callable(item);

All code samples I've seen do:

//some defined member function
Item::Foo(int n);

DoBinding(std::mem_fn(&Item::Foo));

Why can't it simply be:

DoBinding(&Item::Foo);

It seems the latter is callable without having to use std::mem_fn, so why is it needed?

Answer

Barry picture Barry · May 16, 2016

This is because generic code that expects UnaryFunction or BinaryFunction will invoke it directly with the regular call syntax. So to pick an arbitrary algorithm like for_each, it could well be implemented like:

template<class InputIt, class UnaryFunction>
UnaryFunction for_each(InputIt first, InputIt last, UnaryFunction f)
{
    for (; first != last; ++first) {
        f(*first); // <== N.B. f(*first)
    }
    return f;
}

If you called for_each() with &Item::Foo, the code try to call (&Item::Foo)(x), which is ill-formed since for pointers to members you have to write (x.*&Item::Foo)(). It's that syntactical difference that mem_fn is meant to solve: mem_fn deals with the invocation syntax of pointers to members so that you can use all the algorithms with pointers to members as well as functions and function objects. You cannot have for_each(v.begin(), v.end(), &Item::Foo) but you can have for_each(v.begin(), v.end(), mem_fn(&Item::Foo)).

This works just fine in std::bind() (and std::thread and std::function and ...) natively since those all have explicit handling for pointers to members separately. And since DoBinding() itself calls std::bind(), there is no reason for std::mem_fn in this case.


There is was a proposal to get rid of this syntactic difference: P0312. It did not go well.