Friday, April 8, 2011

How to pass and then invoke generic callback functions without causing circular dependency.

Couldn't creatively shorten the title :)

I have been using a variation of the below solution, however I always wondered if there is a better/cleaner way to implement it. I am looking for non-boost solution. We can, though, look at the implementation of boost and C++0x, as it will soon be relevant.

//Notice the use of template template parameter
template <template <typename> class Callback>   
class A {
   Callback <A> m_func;
   public:
     A (Callback <A>  func):  m_func (func) {}
     void call () { m_func(*this);}

};

template <typename T>
struct MYCallback
{
   void operator () (const T&t) {}

};


void Test()
{
   typedef A<MYCallback> AType;

   MYCallback<AType> callback;
   AType a (callback);
   a.call ();

}

Another, a more suncinct way, is to use tr1::function, which will become defuct-to with new standardization:

#include <tr1/functional>


class A {
   std::tr1::function <void (const A&)>  m_func;
   public:
     template <class Callback>
     A (Callback func) :  m_func (func) {}

     void call () { m_func(*this);}

};

template <class T>
struct My_callback
{
   void operator () (const T&t) {}

};

void Test ()
{
   My_callback <A> c;
   A a (c);
   a.call ();
}
From stackoverflow
  • I always believe that void* is your friend when you want elegance in these things.

  • One way you can do it is with a derived class:

    template <class Callback>   
    class A {
       Callback m_func;
       public:
         A (Callback  func):  m_func (func){}
         void call () { m_func(*this);}
    
    };
    
    template <typename T>
    struct MYCallback
    {
       void operator () (const T&t) {}
    
    };
    
    
    struct AConcrete : public A<MYCallback<AConcrete> >
    {
      template <class T>
      AConcrete(T t): A<MYCallback<AConcrete> > (t) {}
    };
    
    void Test()
    {
    
       MYCallback<AConcrete> callback;
       AConcrete a (callback);
       a.call ();
    
    }
    

    PS: Recursion is tough with C++ templates.

  • If you're just looking for clean-up advice, I'd suggest making 'My_callback' a normal class, not a class template. There's not obvious need for it to be a template in this case. Instead, make its apply operator templated or fill in A directly if My_callback only deals with A instances:

    #include <tr1/functional>
    
    class A {
       std::tr1::function <void (const A&)>  m_func;
       public:
         template <class Callback>
         A (Callback func) :  m_func (func) {}
    
         void call () { m_func(*this);}
    
    };
    
    struct My_callback
    {
       template <class T>
       void operator () (const T&t) {}
    };
    
    int main ()
    {
       My_callback c;
       A a (c);
       a.call ();
    }
    

    Otherwise, It looks pretty good as is. Could you be more specific in how you hope to clean it up or simplify it?

0 comments:

Post a Comment