0

I'm working on an Event based architecture for a research project. The system currently uses Qt signalling, but we are trying to move away from Qt, so I need something that will work almost as well as the Qt event loop and signals across threads.

Probably against my better judgement, I've chosen to use variadic templates to create a generic event that will be used to perform the callback in the destination thread.

template<typename dest, typename... args>
class Event {
  public:
    Event(dest* d, void(dest::*func)(args...), args... a)
      : d(d), func(func), pass(a...) { }

    virtual void perform() {
      (d->*func)(pass...);
    }

  protected:

    dest* d;
    void(dest::*func)(args...);
    args... pass;
};

I haven't found anything that indicates if this is possible. However, I have a hard time believing that it isn't. Given that, I was wondering if there is a way to do something like this and if there isn't, why? Also, if anybody has a better way of doing this I would welcome the suggestion.

  • To answer your first question, did you try to compile this? – MSN Sep 30 '10 at 20:35
  • If you want something really similar to Qt signals, but without using Qt, you could try [Boost.Signals](http://www.boost.org/doc/libs/1_43_0/doc/html/signals.html) (or look at the code to draw some inspiration, but they don't use C++0x yet). – Luc Touraille Oct 01 '10 at 06:51
  • Yes I did try to compile this, and the only part that gives trouble is the args... pass at the bottom. – Alex Norton Oct 03 '10 at 08:08
  • -1 for not declaring a clear winner after almost a month (Maister answer is the most clear example i've found of variadic templates so far) – lurscher Nov 27 '10 at 04:54

2 Answers2

2

Hm. I think I got something nasty. The code is not very pretty or good, but you probably get the idea. You should be able to use templates to recursively store objects of any type, and also recurse through them when calling the function.

#include <iostream>

template<typename first_arg, typename... args>
class Event
{
   public:

      Event(void (*fn)(first_arg, args...), first_arg first, args... in) : m_func(fn), var(first, in...) {}

      void operator()()
      {
         var(m_func);
      }

   private:
      void (*m_func)(first_arg, args...);

      template <typename t_arg, typename... t_args>
      struct storage;

      template <typename t_arg>
      struct storage<t_arg>
      {
         storage(t_arg t) : m_var(t) {}

         template<typename t_func, typename... tt_args>
         void operator()(t_func fn, tt_args... p)
         {
            fn(p..., m_var);
         }

         t_arg m_var;
      };

      template <typename t_arg, typename t_arg2, typename... t_args>
      struct storage<t_arg, t_arg2, t_args...>
      {
         storage(t_arg t, t_arg2 t2, t_args... p) : m_var(t), m_storage(t2, p...) {}

         template<typename t_func, typename... tt_args>
         void operator()(t_func fn, tt_args... p)
         {
            m_storage(fn, p..., m_var);
         }

         t_arg m_var;
         storage<t_arg2, t_args...> m_storage;
      };

      storage<first_arg, args...> var;
};

void test(int a, float b)
{
   std::cout << a << std::endl << b << std::endl;
}

int main()
{
   Event<int, float> event(test, 10, 100.0);
   event();
}

Also, I think std::bind does something similar, but not sure :D

Maister
  • 4,978
  • 1
  • 31
  • 34
0

use boost::fusion::make_fused. see example(sorry, japanese...): http://d.hatena.ne.jp/faith_and_brave/20100804/1280905506

Akira Takahashi
  • 2,912
  • 22
  • 107