Search code examples
c++lambdastdbind

Binding a class method to a method of another class


I have two classes where one is logic and one is the model. After initializing both, I would like to bind a b.funB()to a.funA() where A a; B b;.

class A{
   public:
     bool funA() { doStuff(); }
}


class B{
   public:
     bool funB();
    
    Template<class T>
    void bindBtoA((bool (B::*fun2)(), bool (T::*fun1)(), T *t){
       funB=std::bind( ?);
       // (fun1, t), (&T::fun1, &t), (T::fun1, t), ... ?
    }
}

How do I bind these correctly and get rid of "can't convert" errors (I did use typedef in my actual code)

An answer using lambda is acceptable. But, funB needs to be a callable as another engine needs to grab this (hint: Q_INVOKABLE), so using std::function for A::funA might not work for my case.


Solution

  • You can achieve this via the magic of std::function, which would be hidden inside class B and type-erases the function to be called, thereby giving you the generality you seek.

    Here's a fully-worked example:

    #include <iostream>
    #include <functional>
    
    class A
    {
    public:
        bool funA () { std::cout << "funA\n"; return true; }
    };
    
    class B
    {
    public:
        bool funB ()
        {
            return f ();
        }
        
        template <class T>
        void bindBtoA (bool (T::*fun1) (), T *t)
        {
             f = [t, fun1] { return (t->*fun1) (); };
        }
    
    private:    
        std::function <bool ()> f;
    };
    
    int main()
    {
        A a;
        B b;
        b.bindBtoA <A> (&A::funA, &a);
        std::cout << b.funB ();
    }
    

    Live demo

    I would think this would work with Q_INVOKABLE, but I don't actually know anything about it so you'd have to try it. But if it does work, it's a good way to do it.

    Note: With the code as posted, you are responsible for keeping a alive for as long as b is alive. If you can't guarantee that, a better bet would be to use a std::shared_ptr instead. Or copy a inside bindBtoA if that is a practical solution for you (which I'm guessing it isn't).