Search code examples
c++pointer-to-membermember-functions

Can't call stored member function on stored object


I'm trying to create sort of an event system, I don't care if it is suboptimal, I'm doing it for fun. I do not want alternate solutions, I want to understand why this isn't working and how could I fix it.

I'm using this page as reference to do so "https://isocpp.org/wiki/faq/pointers-to-members#fnptr-vs-memfnptr-types"

I want event_triggerer to store the functions it needs to call from event_receiver and be able to call them on the stored object

This is the relevant code:

typedef void(event_receiver::* ev_rec_func)(const event_receiver::Msg&);

class event_receiver {
public:
    struct Msg {
        int irrelevant_test_data;
    };
    virtual void event_callback0(const Msg& m) {};
};

class event_triggerer {
private:
    std::vector<std::pair<event_receiver*, ev_rec_func>> suscribers_vec;
public:
void trigger_event(const event_receiver::Msg& m) {
    for (std::pair<event_receiver*, ev_rec_func>& e : suscribers_vec) {
        //this line show the error expression must have pointer to member type
        e.first->*(e.second(m));
    }
}

Visual Studio displays this when I hover over ev_rec_func:

typedef void ev_rec_func(const &)

But I cannot understand why.
Im not really used to typedef syntax, so I guess there's something wrong with it.

I also found this answer but could not understand whats wrong with mine C++: Calling member function via pointer

I rewrote this line e.first->*(e.second(m)); as "(e.first->*e.second)(m); but it still generates an error, this time is:

"a pointer to a bound function may only be used to call the function"

How can I solve the error ?


Solution

  • There are several issues in your code:

    1. Your typedef for ev_rec_func has to be declared after class event_receiver { ... }; because it refers to event_receiver::... and so event_receiver must already be known.

      Note: you can consider to replace the typedef with a more modern type alias (AKA using declaration):

      using ev_rec_func = void(event_receiver::*)(const event_receiver::Msg&);
      
    2. As @DominikKaszewski commented, you have to change the method invoke syntax to:

       (e.first->*(e.second))(m);
      

      The reason is that it is a matter of Operator Precedence.

    Live demo