C++ : create custom function dispatcher from variadic template

谁都会走 提交于 2019-12-04 12:24:53
Xeo

I have done something similar for my stream_function class. The basic idea is that you pass a type to a function template, which does The Right Thing™, and expand that call:

callback(magic<Args>(/* sth */)...);

However, if your functions aren't pure and modify some state, and as such have the requirement that they need to be called in the correct order, you have to force that order with some tricks.

If you're using Clang, this is rather easy, as it forces left-to-right evaluation for braced-init-lists. This allows you to just use a small helper type

struct invoker{
  template<class F, class... Args>
  invoker(F&& f, Args&&... args){ f(std::forward<Args>(args)...); }
};

and then do

invoker{ callback, magic<Args>(/* sth */)... };

Unfortunately, GCC doesn't yet implement this feature, so one needs to resort to manual order-enforcement. This can be done with a small helper struct which is just a type-list, but allows one to do some useful things:

  • see when the pack is empty (types<>), and
  • process Args in a head-then-tail recursive fashion

template<class...> struct types{};

template<class... Args>
struct dispatcher{
    std::function<void(Args...)> f;

    void call(){ _call(types<Args...>{}); }
private:
    // take head, produce value from it, pass after other values
    template<class Head, class... Tail, class... Vs>
    void _call(types<Head, Tail...>, Vs&&... vs){
        _call(types<Tail...>{}, std::forward<Vs>(vs)..., get_value<Head>());
    }

    // no more values to produce, forward to callback function
    template<class... Vs>
    void _call(types<>, Vs&&... vs){ f(std::forward<Vs>(vs)...); }
};

Live example.

Something like this can help you

template<typename T>
T get_value(Deserializer&);

template<>
int get_value(Deserializer& d)
{
   return d.getInt();
}

template<>
std::string get_value(Deserializer& d)
{
   return d.getString();
}

template<typename... Args>
class Dispatcher
{
public:
   template<typename Functor>
   Dispatcher(Deserializer& d, const Functor& cb) : myDeserializer(d), callback(cb)
   {
   }
   void dispatch()
   {
      callback(get_value<Args>(myDeserializer)...);
   }
private:
   std::function<void(Args...)> callback;
   Deserializer myDeserializer;
};

Live example

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!