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

How to switch with pointer to member functions?


Well, all I want to do is a "switch" with a function pointer, but with methods pointers. The switch is that if I call the method Run(), it will either redirect to A::RunOn() or A::RunOff() according to Run ptr is pointing to these member functions.

I know it can be done. I did it in plain but I have searched and googled to do the same thing in but no luck.

class A
{
    typedef (void)(A::*RunPtr)(int);
    RunPtr RunMethod;

public:
    RunMethod Run;

    A()
    {
        Run = RunOff;
    }

    void SetOn(bool value)
    {
        if (value)
            Run = RunOn;
        else
            Run = RunOff;
    }

    void RunOn(int)
    {
        // RunOn stuff here
    }

    void RunOff(int)
    {
        // RunOff stuff here
    }
};

So I can call Run() and there will be a switch between the function calls, which I think is more efficient than just doing:

if (on)
    RunOn();
else
    RunOff();

Don't know how to do it!


Solution

  • Your member function pointer typedef is wrong (Despite the other issues in the shown code). You need

    typedef void(A::*RunPtr)(int);
    

    Or you can provide the alias for the member function pointer of class A with the help of using keyword as follows:

    using RunPtr = void(A::*)(int);
    RunPtr RunMethod;
    

    Now in the SetOn you can do member pointer assignment as follows

    void SetOn(bool value)
    {
        RunMethod = value ? &A::RunOn : &A::RunOff;
    }
    

    Now, in order to call the stored member function pointer, you may/ can provide a Run member function as follows:

    void  Run(int arg)
    {
        std::invoke(RunMethod, this, arg);
        // do something...
    }
    

    The call to member function is a bit tricky. However, this can be done using more generic std::invoke from <functional> header (Since ).

    Here is the complete example:

    #include <iostream>
    #include <functional> //  std::invoke
    
    class A
    {
        using RunPtr = void(A::*)(int);
        // or with typedef
        // typedef void(A::*RunPtr)(int);
        RunPtr RunMethod;
    
    public:
        void SetOn(bool value)
        {
            RunMethod = value ?  &A::RunOn : &A::RunOff;
        }
    
        void  Run(int arg)
        {
            std::invoke(RunMethod, this, arg);
            // do something...
        }
    
        void RunOn(int arg) { std::cout << "RunOn: " << arg << "\n"; }
    
        void RunOff(int arg) { std::cout << "RunOff: " << arg << "\n";  }
    };
    
    int main()
    {
        A obj;
        obj.SetOn(true);
        obj.Run(1);       // prints: RunOn: 1  
        obj.SetOn(false);
        obj.Run(0);       // prints: RunOff: 0
    }
    

    (See a Demo)