HGWantToLearn
HGWantToLearn

Reputation: 11

Passing Member Function Pointer into a Template

First of all sorry for the title being confusing. Here's my OOP setup. I have base class Base, and two pure virtual functions add and multi. Then I have derived classes D1 and D2 and I implement the add and multi functions. I want to have a template function, that can have the flexibility that can switch between D1 D2 and calling add or multi functions. I googled around and someone people saying I should use function pointers but some others say it does not work with pure virtual functions.

class Base
{ double data; //data member
  Base(double d):data(d){}; 
  virtual double add() = 0; 
  virtual double multi() = 0; 
}
class D1::public Base
{ D1(double d): Base(d) {}; //calling base class constructor
  double add() {return data+1;} ;
  double multi() {return data*2;} ;
}
class D2::public Base
{ D2(double d): Base(d) {}; //calling base class constructor
  double add() {return data+3;} ;
  double multi() {return data*4;} ;
}
//now I want to have a template function that give me flexibility to construct D1 or D2 and calling add or multi.
template <typename T, typename F> 
void testFun(double num)
{ T tmp(num); //create object either D1 or D2;
  cout << T->F() << endl; //calling either add or multi;
}
int main()
{ testFun<D1, D1.add()>(double x = 5); 
//i know passing in D1.add() is wrong i don't know how to fix, hopefully you know what I am trying to achieve
  return 0;}

Any help will be appreciated. Thank you guys.

Upvotes: 1

Views: 519

Answers (1)

cdhowie
cdhowie

Reputation: 169318

There's nothing about virtual member functions that makes pointers to member functions not work. You can invoke a pointer to a pure virtual function if the object being invoked on is a pointer/reference to an object that has an actual implementation.

It looks like you're getting tripped up on the syntax of exactly how to pass a pointer-to-member-function in the first place.

Also note that virtual dispatch wouldn't even be used here since the type of object being used is known at compile time.

template <typename T> 
void testFun(double num, double (T::*fn)())
{
    T tmp(num);
    std::cout << (tmp.*fn)() << std::endl;
}

Here, fn is a pointer to a member function of T that accepts no arguments and returns a double value. You can invoke it like so:

testFun<D1>(5, &D1::add);

Note some other errors with the example code you've given:

  • You specify base types with :: when you should use :. For example: class D1 : public Base.
  • You use class but never specify an access modifier, which means all members are implicitly private. For the purposes of the demo, changing them to struct (which defaults to public access) fixes this.
  • You need a semicolon after a class/struct definition.

Here is a demo of the working code.


Just for the sake of completeness, here is a demo showing that you can use a pointer to a pure-virtual member function to invoke on a reference/pointer to a derived type. The code has to be adjusted to use a D1 or D2 object through a reference of Base for the dispatch to be dynamic. This example looks like:

template <typename T> 
void testFun(double num, double (Base::*fn)())
{
    T tmpConcrete(num);
    Base & tmp = tmpConcrete;
    std::cout << (tmp.*fn)() << std::endl;
}

int main() {
    testFun<D1>(5, &Base::add);
}

(Of course, here it's a bit silly to use a pointer to a Base member when the generic code knows what T is, but it proves the point that it's possible.)

Upvotes: 2

Related Questions