Converting C++ Member Functions into Function Objects
C++ c++ stl
Published: 2007-08-28
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:

1
2
3
4
5
template <typename _Fn>
void call_functor(_Fn fn)
{
    fn();
}

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

1
2
3
4
5
6
7
class C
{
    void foo() { std::cout << "foo()\n"; }
};

C c;
call_functor(/\* What do I put here? c.foo 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:

1
2
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.

1
2
3
4
5
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:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
template <typename _Func, typename _P1>
class binder
{
public:
    binder(_Func func, _P1 p1) :
        func_(func), p1_(p1) {}
    void operator()() const { return func_(p1_); }

private:
    _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():

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

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

1
2
3
#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.