How best to pass methods into methods of one class

I have this C ++ class, which is one complex compute method that I would like to handle using the "compute core", a method of the same class. I believe that I will do something in accordance with

 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 to get through add or multiply . An alternative to this approach would be to pass ENUM some kind to indicate add() or multiply() , but I wanted to avoid switch or if inside loops.

What is the best practice here?

+7
source share
3 answers

As you suspected, passing a member function pointer is acceptable practice.

If you need to know the syntax, this is:

 int compute_(int a, int b, int (test::*f)(int,int)) { int c=0; // Some complex loops { c += (this->*f)(a,b) // } return c; } 

Representing member functions using integers and switching introduces the overhead of the programmer to update the list of available operations. Therefore, you do not want this, if in a particular case there is no important reason.

One option is to make compute even more general - instead of accepting a member function, write a function template that accepts any type being called:

 template <typename BinaryFunction> int compute_(int a, int b, BinaryFunction f) { // body as before but `f(a,b)` instead of `(this->*f)(a,b)` } 

This more general pattern is great if someone wants to use it with some kind of operator of their invention, which is not a test member function. However, it is harder to use in the case of a member function, because someone needs to capture this . There are several ways to do this - C ++ 11 lambda, boost::bind or write a long handwriter. For example:

 template <typename BinaryFunction> int compute_(int a, int b, BinaryFunction f) { // body as before with `f(a,b)` } int compute_(int a, int b, int (test::*f)(int,int)) { return compute_(a, b, bind_this(f, this)); } 

The definition of bind_this bit painful: it likes std::bind1st , except that we would like to work with a 3-arg functor, whereas bind1st only accepts a binary functor. boost::bind and std::bind in C ++ 11 are more flexible and will handle extra arguments. For this case, the following will be executed, but does not work at all for linking 2-arg member functions:

 struct bind_this { int (test::*f)(int,int); test *t; int operator(int a, int b) const { return (t->*f)(a,b); } bind_this(int (test::*f)(int,int), test *t) : f(f), t(t) {} }; 

In C ++ 11, you can just use lambda:

 int compute_(int a, int b, int (test::*f)(int,int)) { return compute_(a, b, [=](int c, int d){ return (this->*f)(c,d) }); } 
+5
source

You have two alternatives:

An example of using a pointer to a member function:

 #include <iostream> class D { public: D(int v ) : classVar_(v){} int add_(int a, int b){return (a+b+classVar_);} int multiply_(int a, int b){return (a*b+classVar_);} private: int classVar_; }; class test { public: int compute_(int a, int b, D &d, int (D::*f)(int a, int b)) { int c=0; // Some complex loops { c += (d.*f)(a,b); // } return c; } }; int main() { test test; D d(1); std::cout<<"add : " << test.compute_( 5, 4, d, &D::add_ ) << std::endl; std::cout<<"add : " << test.compute_( 5, 4, d, &D::multiply_ ) << std::endl; } 

An example of using lambda:

 #include <iostream> #include <functional> class D { public: D(int v ) : classVar_(v){} int add_(int a, int b){return (a+b+classVar_);} int multiply_(int a, int b){return (a*b+classVar_);} private: int classVar_; }; class test { public: int compute_(int a, int b, std::function< int(int,int) > f) { int c=0; // Some complex loops { c += f(a,b); // } return c; } }; int main() { test test; D d(1); std::cout<<"add : " << test.compute_( 5, 4, [&d](int a, int b){ return d.add_(a,b); } ) << std::endl; std::cout<<"add : " << test.compute_( 5, 4, [&d](int a, int b){ return d.multiply_(a,b); } ) << std::endl; } 
+1
source

Use function pointers.

 int compute(int a, int b, int (test::*f) (int, int) ) { int c=0; // Some complex loops { c += (this->*f)(a,b) // } return c; } 
+1
source

All Articles