C ++: creating a custom function manager from a variational template

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

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

Then I have various callback functions that take arbitrary parameters, for example:

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

I want to call various callbacks with arguments read from a deserialized data stream. I would like to automate the template code as much as possible. I was thinking maybe I can use patterns. If I had some Dispatcher class, for example:

 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 send, I simply call:

 myDispatcherB.dispatch(); 

which underneath will expand like this:

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

Is this possible with C ++ 11 variation patterns? I read them a bit, and it seems that recursion is used a lot.

+2
c ++ templates variadic
Sep 17 '13 at 10:30
source share
2 answers

I did something similar for the stream_function class. The basic idea is that you pass the type to the function template that The Right Thing β„’ does, and extend this call:

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

However, if your functions are not clean and change some state, and as such have a requirement that they need to be called in the correct order, you need to force this order with some tricks.

If you use Clang, this is pretty easy, as it gives a left-to-right rating for braced-init lists. This allows you to simply 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 does not yet implement this function, so you need to resort to manual tidying. This can be done using a small helper structure, which is just a list of types, but allows you to do some useful things:

  • see when the package is empty ( types<> ), and
  • process Args in recursive mode with a header



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

Real-time example.

+5
Sep 20 '13 at 10:15
source share

Something like this might 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; }; 

Living example

+1
Sep 17 '13 at 10:46
source share



All Articles