It depends on whether the arguments to the private functions are similar or not. The following solutions are possible, ranging from simple and limited to complex and generic:
- Equivalent =< Use member-function-pointer)
- Same number, different types => Templatize over each argument)
- Different numbers/types of arguments => se boost::bind and function objects)
Thanks for the comments given. At first, I only posted the first solution, but there are (as listed) other situations that need different approaches.
Member-function-pointer:
bool Node::walker_caller(Arg* arg1, bool (Node::*memfn)(Arg*, bool))
{
...
if( (this->*memfn)(arg1, shouldReturn) ) //This line alone varies
return true;
...
}
bool Node::some_walker(Arg* arg1)
{
return walker_caller(arg1, &Node::some_walker_p);
}
bool Node::other_walker(Arg* arg1)
{
return walker_caller(arg1, &Node::other_walker_p);
}
Sidenote: I usually typedef the mem-fn-ptr to make the syntax more bearable.
Templated arguments:
I assume you always have two arguments here, but they can have different types.
If you have a limited amount of args-numbers (say 1 and 2), you can could implement walker_caller twice, one impl for one-arg and one for two-arg, both templated.
template<class A1, class A2)
bool Node::walker_caller(A1 arg1, A2 arg2, bool (Node::*memfn)(A1, A2, bool))
{
...
if( (this->*memfn)(arg1, arg2, shouldReturn) ) //This line alone varies
return true;
...
}
bool Node::some_walker(Arg* arg, OtherArg* other_arg)
{
return walker_caller(arg, other_arg, &Node::some_walker_p);
}
bool Node::other_walker(OtherArg* other_arg, YetAnotherArg* yaa)
{
return walker_caller(other_arg, yaa, &Node::other_walker_p);
}
Function objects:
If your walkers use widely different number and argument types, you probably want to use boost::bind, and maybe boost::function. (Use of the latter is not required but cuts down on the generated code size...)
// faster code, as the function object may be inlined, but
// each call instantiates a different walker_caller, so exe might be bigger
template<class F>
bool Node::walker_caller(const F& fn)
{
...
if( fn(shouldReturn) ) //This line alone varies
return true;
...
}
// only one implementation, so smaller foot print but
// all arguments need to be copied into a function objet
// which may be a perf hit if the arguments are big
// (this version is good to have when you inherit from Node...)
bool Node::walker_caller(const boost::function<bool (bool)>& fn)
{
...
if( fn(shouldReturn) ) //This line alone varies
return true;
...
}
bool Node::some_walker(Arg* arg1)
{
return walker_caller(boost::bind(&Node::some_walker_p, this, arg1, _1));
}
bool Node::other_walker(Arg* arg1, OtherArg* arg2)
{
return walker_caller(boost::bind(&Node::some_walker_p, this, arg1, arg2, _1));
}