3

I want to create a method schedule_function which saves a pointer to a member function of a BasicAlgo object into a ScheduledEvent, but not have said function defined in BasicAlgo's parent class, Strategy. Right now I am using this method which works fine for saving functions in Strategy but will not work for BasicAlgo functions:

class Strategy {

schedule_function(void (Strategy::*func)()) {
    // Puts the scheduled event built with the strategy function onto a list
    heap_eventlist.emplace_back(std::make_unique<events::ScheduledEvent>(func));
}}

I tried replacing Strategy::*func with Strategy*::*func but that caused compiler errors and it doesn't seem correct.

Is there any way to have a pointer to a member function from derived class BaseAlgo as a parameter in the base class, Strategy, without defining the function in Strategy?

  • Possible duplicate of [Why can't I cast a pointer to Derived class member function to the same but of class Base?](https://stackoverflow.com/q/10162823/608639) – jww Oct 12 '18 at 00:29

2 Answers2

2

There's no way you can store a member function of BaseAlgo in a pointer to member function of Strategy.

You can store a member function of BaseAlgo in a pointer to member function of BaseAlgo, and you can use such pointer type with CRTP:

template<class T>
struct Strategy {
    void schedule_function(void (T::*func)());
};

struct BasicAlgo : Strategy<BasicAlgo> {
    void memfun();
};

int main() {
    BasicAlgo b;
    b.schedule_function(&BasicAlgo::memfun);
}

Otherwise, you could use a type-erasing function wrapper such as std::function instead of a function pointer.

eerorika
  • 232,697
  • 12
  • 197
  • 326
  • This looks very promising––however, in the implementation (.cpp file) of schedule_function it doesn't allow me to change the parameter to `void (T::*func)()`. Do I keep it the same way using `void (Strategy::*func)()` while using `void (T::*func)()` in the header declaration? – Evan Kirkiles Oct 11 '18 at 23:44
  • 1
    @EvanKirkiles If you want to use a template in more than one translation unit, you'll need to put the function definitions into the header. – eerorika Oct 11 '18 at 23:57
2

It is not possible to store a derived class function pointer in a base class function pointer.

An alternative is to store a function with a Strategy* argument:

class Strategy {
    ...
    void schedule_function(function<void(Strategy*)> func) {
        heap_eventlist.emplace_back(std::make_unique<ScheduledEvent>(func));
    }
}; 

You can then simply use directly a member function of Strategy:

BasicAlgo g;
g.schedule_function (&BasicAlgo::f);   // f is a member function of Strategy

But you can also provide any other function that accepts a Strategy pointer as argument. If your Strategy is a polymorphic class, you can then attempt to safely downcast the Strategy pointer and call a member function of the derived class.

g.schedule_function ([](Strategy *x)->void {
                       BasicAlgo*b=dynamic_cast<BasicAlgo*>(x); 
                       if (b) b->ff(); 
                    });

Here a demo.

Christophe
  • 68,716
  • 7
  • 72
  • 138
  • +1 for great solution as well! However, I'm trying to keep the schedule_function easy to implement for others though and these lambdas are a bit more complex to use than user207's answer. – Evan Kirkiles Oct 11 '18 at 23:57