Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ Use template class to call non static member function

I am trying to use a template class as a work around for callback. I want to use a non-static member function for callbacks.

I created two classes:

//First Class
class AbstractAction
{
public:
  AbstractAction() = default;
  virtual ~AbstractAction() = 0;

  virtual void exec() = 0;
};

//Second class
template<class T>
class Action: public AbstractAction
{
public:

  Action<T>(T* obj, void (T::*func)())
  : class_obj_(obj), class_func_(func) {}

  virtual void exec() {class_obj_->*class_func_;}

private:
  T * class_obj_;
  void (T::*class_func_)();

};

In my Code I have a class called "Button". This class has a member of AbstractAction. When the Button is pressed it calls the exec() function. exec() is virtual so actually the function of Action<SomeClass> is called.

Now I create a class using an Object of Action

class HardWork
{
public:
  HardWork()
  : action(this, &HardWork::workOnAction)  {}

private:
  void workOnAction() { /* do something using non static variables */ };

  Action<HardWork> action;
};

And the compile says:

In instantiation of 'void display::Action<T>::exec() [with T = HardWork]':
error: invalid use of non-static member function of type 'void (HardWork::)()'
   virtual void exec() {class_obj_->*class_func_;}
                        ^~~~~~~~~~

Why does he complain about this? He has a pointer to an actual object of Hardwork so he should know what to call. Second and more important what way around do I have. I don't want to use the static work around. What options do I have?

like image 934
emp Avatar asked Jan 21 '26 03:01

emp


2 Answers

When you do

class_obj_->*class_func_;

you dereference the function pointer but you don't actually do anything with it. You still need to call the fuction like you normally would. You do need to add some extra parentheses to do this though and that would look like

virtual void exec() { (class_obj_->*class_func_)();}
                      ^^^^^get function^^^^^^^^^ ^
                                                 | call function 
like image 90
NathanOliver Avatar answered Jan 22 '26 18:01

NathanOliver


To avoid messy syntax of calling through a member function pointer, std::invoke can be used since C++17:

virtual void exec() {
    std::invoke(class_func_, class_obj_);
}
like image 24
Evg Avatar answered Jan 22 '26 17:01

Evg



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!