Search code examples
c++templatesdelegatesvariadic-templatespointer-to-member

C++ delegate template


If I have the following setup, just example. The problem I have is to get the connect function of the template to work.

class A
{
public:
   Delegate<void(int)> test;
};


class B
{
public:
    void test(int a)
    {
       std::cout << a;
    };

};

I want to connect this with the following: a.test.connect(&b, &B::test);

Then an instance of class a can call the test function on an instance of class B.

I have the following template, but have problem to capture the instance and function I need.

#ifndef DELEGATE_H
#define DELEGATE_H

#include <functional>

template<class _Delegate>
class Delegate;


template<class R, class... Args>
class Delegate<R(Args...)>
{
public:
    template<typename T>
    void connect(T* t, R(Args... ) ) 
    {
        mFunction = std::function(T::*t, R(Args...));; 

    }

    R operator()(Args... args)
    {
        return mFunction(args...);
    }

protected:
    std::function<R(Args...)> mFunction;
};

#endif

Solution

  • Your connect() should be written almost as follows

      template<typename T>
      void connect (T * t, R(T::*method)(Args...) ) 
       { mFunction = [=](Args ... as){ (t->*method)(as...); }; }
    

    The following is a full compiling example

    #include <iostream>
    #include <functional>
    
    template <typename>
    class Delegate;
    
    template <typename R, typename... Args>
    class Delegate<R(Args...)>
     {
       public:
          template<typename T>
          void connect (T * t, R(T::*method)(Args...) ) 
           { mFunction = [=](Args ... as){ (t->*method)(as...); }; }
    
          R operator() (Args... args)
           { return mFunction(args...); }
    
       protected:
          std::function<R(Args...)> mFunction;
     };
    
    class A
     { public: Delegate<void(int)> test; };
    
    class B
     { public: void test (int a) { std::cout << a; }; };
    
    int main()
     {
       A a;
       B b;
    
       a.test.connect(&b, &B::test);
    
       a.test(42);
     }