Casey Anderson
Casey Anderson

Reputation: 343

C++ Pointer to a member function of any class with matching function signatures

How do I assign references of non-static member functions, with identical signatures, but from different classes, to a function pointer with a matching signature?

I can do this with the aid of std::function from the C++ std library. I also do this all the time with regular C functions and no help from the std library. I am writing firmware and code-space is limited. If helpers from the C++ std library can do it, surely it must be possible to do it manually using purely C/C++ language constructs (pre C++11 preferred).

Example code demonstrating my intention:

class A {
public:
    void ping_event_handler();
};

class B {
public:
    void ping_event_handler();
};

void A::ping_event_handler_A() {
    // Handle ping event in A...
}

void B::ping_event_handler_B() {
    // Handle ping event in B...
}

void ping_event_handler_C() {
    // Handle ping event in normal function...
}

int main() {

    // Ping event "pointer to a function that takes no arguments"
    void (*ping_event)();

    A a();
    B b();

    ping_event = a.ping_event_handler; // Attach class A's handler
    ping_event();                      // Trigger event

    ping_event = b.ping_event_handler; // Attach class B's handler
    ping_event();                      // Trigger event

    ping_event = ping_event_handler;   // Attach non-class handler
    ping_event();                      // Trigger event

}

Upvotes: 2

Views: 1484

Answers (1)

Jarod42
Jarod42

Reputation: 217293

The old way is to pass an userData with the function

void (*ping_event)(void* userData);

and save both the function and userData. then in user side, casting the userData in it class and calling any method from it:

struct my_function
{
    my_function(void (*f)(void*), void* userData) : mF(f), mUserData(userData)
    {}

    void set(void (*f)(void*), void* userData)
    {
         mF = f;
         mUserData = userData;
    }

    void operator() () {
        mF(mUserData);
    }
    void (*mF)(void*);
    void* mUserData;
};

And at the call site:

template <typename C, void (C::*m)()>
void my_func_helper(void* userData)
{
    C* c = static_cast<C*>(userData);
    (c->*m)();
}


int main()
{
    A a;

    my_function f(&my_func_helper<A, &A::ping_event_handler>, &a);

    f();

    B b;

    f.set(&my_func_helper<B, &B::ping_event_handler>, &b);
    f();

    f.set(ping_event_handler_c, NULL);
    f();
}

Demo

Upvotes: 1

Related Questions