expanded parameter list for variadic template

2020-06-30 04:15发布

问题:

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.

回答1:

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



回答2:

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