C++:从可变参数模板创建自定义函数调度程序 [英] C++ : create custom function dispatcher from variadic template

查看:29
本文介绍了C++:从可变参数模板创建自定义函数调度程序的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一些函数可以从序列化数据中读取各种类型,例如:

I have some functions that read various types from serialized data, eg:

class DataDeserializer
{
    int getInt();
    std::string getString();
    MyClass getMyClass();
}

然后我有各种带任意参数的回调函数,例如:

I then have various callback functions that take arbitrary parameters, eg:

void callbackA (int, int, int);
void callbackB (int, std::string);
void callbackC (std::string, int, MyClass, int);

我想使用从反序列化数据流中读取的参数调用各种回调.我想要的是尽可能自动化样板代码.我在想也许我可以使用模板.如果我有某种调度员类,例如:

I want to call the various callbacks with arguments read from the deserialized data stream. What I would like is to automate the boilerplate code as much as possible. I was thinking maybe I could use templates. If I had some sort of Dispatcher class, eg:

template <SOMETHING??> class Dispatcher
{
    void dispatch()
    {
        // ???? 
    }

    SOMEFUNCTIONTYPE callback;
    DataDeserializer myDeserializer;
};

然后声明各种特定的调度器:

Then declare various specific dispatchers:

Dispatcher<int,int,int>                  myDispatcherA (deserializer, callbackA);
Dispatcher<int,std::string>              myDispatcherB (deserializer, callbackB);
Dispatcher<std::string,int,MyClass,int>  myDispatcherC (deserializer, callbackC);

然后当我想调度时,我就打电话:

Then when I want to dispatch, I just call:

myDispatcherB.dispatch();

下面会扩展成这样:

void dispatch()
{
    callback (myDeserializer.getString(), myDeserializer.getInt(), myDeserializer.getMyClass(), myDeserializer.getInt());
}

这可以用 C++11 可变参数模板实现吗?我已经阅读了一些关于它们的内容,似乎递归使用了很多.

Is this possible with C++11 variadic templates? I've read up a little on them, and it seems recursion is used a lot.

推荐答案

我已经为我的 stream_function 类.基本思想是将类型传递给执行 The Right Thing™ 的函数模板,然后扩展该调用:

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.

如果您使用 Clang,这很容易,因为它强制对支撑初始化列表进行从左到右的评估.这允许你只使用一个小的辅助类型

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)...); }
};

然后做

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

不幸的是,GCC 尚未实现此功能,因此需要手动执行命令.这可以通过一个小的辅助结构来完成,它只是一个类型列表,但允许做一些有用的事情:

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:

  • 查看包何时为空(types<>),以及
  • 以头尾递归的方式处理Args
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)...); }
};

活例子.

这篇关于C++:从可变参数模板创建自定义函数调度程序的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆