我有一些从序列化数据中读取各种类型的函数,例如:
class DataDeserializer
{
int getInt();
std::string getString();
MyClass getMyClass();
}
然后我有各种带有任意参数的回调函数,例如:
void callbackA (int, int, int);
void callbackB (int, std::string);
void callbackC (std::string, int, MyClass, int);
我想调用带有从反序列化数据流中读取的参数的各种回调。 我想要的是尽可能自动化样板代码。 我想也许我可以使用模板。如果我有某种Dispatcher 上课,例如:
template <SOMETHING??> class Dispatcher
{
void dispatch()
{
// ????
}
SOMEFUNCTIONTYPE callback;
DataDeserializer myDeserializer;
};
然后宣布各种特定的调度员:
Dispatcher<int,int,int> myDispatcherA (deserializer, callbackA);
Dispatcher<int,std::string> myDispatcherB (deserializer, callbackB);
Dispatcher<std::string,int,MyClass,int> myDispatcherC (deserializer, callbackC);
然后,当我想发送时,我只是打电话:
myDispatcherB.dispatch();
下面会扩展到这样的东西:
void dispatch()
{
callback (myDeserializer.getString(), myDeserializer.getInt(), myDeserializer.getMyClass(), myDeserializer.getInt());
}
C ++ 11可变参数模板可以实现吗?我已经阅读了一些关于它们的内容,似乎递归使用了很多。
答案 0 :(得分:6)
我为stream_function
课做过类似的事情。基本的想法是你将一个类型传递给一个功能模板,它执行The Right Thing™,并扩展该调用:
callback(magic<Args>(/* sth */)...);
但是,如果你的函数不是纯粹的并且修改某些状态,并且因此要求它们需要以正确的顺序调用,你必须用一些技巧强制执行该命令。
如果你正在使用Clang,这很容易,因为它强制对braced-init-lists进行从左到右的评估。这允许您只使用一个小助手类型
struct invoker{
template<class F, class... Args>
invoker(F&& f, Args&&... args){ f(std::forward<Args>(args)...); }
};
然后再做
invoker{ callback, magic<Args>(/* sth */)... };
不幸的是,GCC尚未实现此功能,因此需要采用手动订单执行。这可以通过一个小的帮助器结构来完成,它只是一个类型列表,但允许人们做一些有用的事情:
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)...); }
};
答案 1 :(得分:2)
这样的事可以帮到你
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;
};