I have this C++ class that one big complicated method compute that I would like to feed with a “compute kernel”, a method of the same class. I figure I would do something along the lines of
class test {
int classVar_ = 42;
int compute_add(int a, int b)
{
compute(int a, int b, this->add_())
}
int compute_mult(int a, int b)
{
compute(int a, int b, this->mult_())
}
int compute_(int a, int b, "pass in add or multiply as f()")
{
int c=0;
// Some complex loops {
c += f(a,b)
// }
return c;
}
int add_(int a, int b){a+b+classVar_;}
int multiply_(int a, int b){a*b+classVar_;}
...
}
but I’m not sure how I would pass in add or multiply.
An alternative to this approach would be to pass in an ENUM of some sort to specify add() or multiply(), but I wanted to avoid a switch or if inside the loops.
What’s best practice here?
As you suspected, passing a member function pointer is acceptable practice.
If you need to know the syntax, it is:
Representing member functions using integers, and switching, introduces programmer overhead to keep things up to date when the list of available operations changes. So you don’t want that unless there’s some important reason in a particular case.
One alternative is to make
computeeven more general — instead of taking a member function, write a function template that takes any callable type:This more general template is great if someone wants to use it with some operator of their own invention, that isn’t a member function of
test. It’s more difficult to use in the case of the member function, though, because someone needs to capturethis. There are a few ways to do that — a C++11 lambda,boost::bind, or writing out a functor longhand. For example:Defining
bind_thisis a bit of a pain: it’s likestd::bind1stexcept that we’d like to work with a 3-arg functor whereasbind1stonly takes a binary functor.boost::bind, andstd::bindin C++11, are more flexible, and will handle the extra arguments. The following will do for this case, but doesn’t work in general to bind 2-arg member functions:In C++11 you can just use a lambda: