Converting C++ Member Functions into Function Objects

Let’s say you have a C++ function that takes a function object as a parameter and calls it:

template <typename _Fn>
void call_functor(_Fn fn)

Now let’s say you want to pass a class’s member function to call_functor() above, as in:

class C
    void foo() { std::cout << "foo()\n"; }
C c;
call_functor(/* What do I put here? and &C::foo don’t work */);

The STL has a pointer-to-member function adapter called std::mem_fun() which almost gets us there. Unfortunately, it doesn’t quite meet our needs because it requires us to pass a pointer to an instance of C, as in:

C c;
std::mem_fun(&C::foo)(&c); // The &c is the problem

However, we can use std::mem_fun() if we could figure out a way to create a new functor around std::mem_fun() with &c bound as its first parameter. Unfortunately, we cannot use the STL binders (std::bind1st and std::bind2nd) because they only work on binary functions, not unary functions.

In the general case, you should use Boost’s very powerful binding library bind. However, let’s write our own simple binder for expository purposes.

First, we need a function, bind(), that returns a function object which binds a parameter, p1, to a unary function object, func. We’ll call the returned function object binder.

template <typename _Func, typename _P1>
inline binder<_Func, _P1> bind(_Func func, _P1 p1)
    return binder<_Func, _P1>(func, p1);

The class binder should store func and p1 and have an operator() which calls func with p1 as its parameter. For simplicity we’ll assume func returns void:

template <typename _Func, typename _P1>
class binder
    binder(_Func func, _P1 p1) :
        func_(func), p1_(p1) {}
    void operator()() const { return func_(p1_); }
    _Func func_; // The functor to apply
    _P1 p1_; // The first paramter

We can now solve the initial problem by combining our bind() with std::mem_fun():

call_functor(bind(std::mem_fun(&C::foo), &c));

We can make usage a little more convenient by introducing a macro:

#define mem_fun_functor(c, memFn) bind(std::mem_fun(memFn), &c)
call_functor(mem_fun_functor(c, &C::foo));

There’s plenty of room for improvements, but it’s amazing what you can do with a little template trickery.

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )


Connecting to %s