Simplification of patterns

I have a bunch of templates that are used for rpc, and wondered if there is a way to simplify them, as he repeats it himself. I know that varags for templates is included in the following standard, but can you use the default values ​​for templates?

Also, is there a way to handle void return functions like regular functions? Atm I have to separate them and treat them as two different things, each of which is due to the fact that templates do not collect void as a type.

template <typename R> R functionCall(IPC::IPCClass* c, const char* name) { IPC::IPCParameterI* r = c->callFunction( name, false ); return handleReturn<R>(r); } template <typename R, typename A> R functionCall(IPC::IPCClass* cl, const char* name, A a) { IPC::IPCParameterI* r = cl->callFunction( name, false, IPC::getParameter(a)); return handleReturn<R>(r); } template <typename R, typename A, typename B> R functionCall(IPC::IPCClass* cl, const char* name, A a, B b) { IPC::IPCParameterI* r = cl->callFunction( name, false, IPC::getParameter(a), IPC::getParameter(b) ); return handleReturn<R>(r); } template <typename R, typename A, typename B, typename C> R functionCall(IPC::IPCClass* cl, const char* name, A a, B b, C c) { IPC::IPCParameterI* r = cl->callFunction( name, false, IPC::getParameter(a), IPC::getParameter(b), IPC::getParameter(c) ); return handleReturn<R>(r); } template <typename R, typename A, typename B, typename C, typename D> R functionCall(IPC::IPCClass* cl, const char* name, A a, B b, C c, D d) { IPC::IPCParameterI* r = cl->callFunction( name, false, IPC::getParameter(a), IPC::getParameter(b), IPC::getParameter(c), IPC::getParameter(d) ); return handleReturn<R>(r); } template <typename R, typename A, typename B, typename C, typename D, typename E> R functionCall(IPC::IPCClass* cl, const char* name, A a, B b, C c, D d, E e) { IPC::IPCParameterI* r = cl->callFunction( name, false, IPC::getParameter(a), IPC::getParameter(b), IPC::getParameter(c), IPC::getParameter(d), IPC::getParameter(e) ); return handleReturn<R>(r); } template <typename R, typename A, typename B, typename C, typename D, typename E, typename F> R functionCall(IPC::IPCClass* cl, const char* name, A a, B b, C c, D d, E e, F f) { IPC::IPCParameterI* r = cl->callFunction( name, false, IPC::getParameter(a), IPC::getParameter(b), IPC::getParameter(c), IPC::getParameter(d), IPC::getParameter(e), IPC::getParameter(f) ); return handleReturn<R>(r); } inline void functionCallV(IPC::IPCClass* cl, const char* name) { IPC::IPCParameterI* r = cl->callFunction( name, false ); handleReturnV(r); } template <typename A> void functionCallV(IPC::IPCClass* cl, const char* name, A a) { IPC::IPCParameterI* r = cl->callFunction( name, false, IPC::getParameter(a)); handleReturnV(r); } template <typename A, typename B> void functionCallV(IPC::IPCClass* cl, const char* name, A a, B b) { IPC::IPCParameterI* r = cl->callFunction( name, false, IPC::getParameter(a), IPC::getParameter(b) ); handleReturnV(r); } template <typename A, typename B, typename C> void functionCallV(IPC::IPCClass* cl, const char* name, A a, B b, C c) { IPC::IPCParameterI* r = cl->callFunction( name, false, IPC::getParameter(a), IPC::getParameter(b), IPC::getParameter(c) ); handleReturnV(r); } template <typename A, typename B, typename C, typename D> void functionCallV(IPC::IPCClass* cl, const char* name, A a, B b, C c, D d) { IPC::IPCParameterI* r = cl->callFunction( name, false, IPC::getParameter(a), IPC::getParameter(b), IPC::getParameter(c), IPC::getParameter(d) ); handleReturnV(r); } template <typename A, typename B, typename C, typename D, typename E> void functionCallV(IPC::IPCClass* cl, const char* name, A a, B b, C c, D d, E e) { IPC::IPCParameterI* r = cl->callFunction( name, false, IPC::getParameter(a), IPC::getParameter(b), IPC::getParameter(c), IPC::getParameter(d), IPC::getParameter(e) ); handleReturnV(r); } template <typename A, typename B, typename C, typename D, typename E, typename F> void functionCallV(IPC::IPCClass* cl, const char* name, A a, B b, C c, D d, E e, F f) { IPC::IPCParameterI* r = cl->callFunction( name, false, IPC::getParameter(a), IPC::getParameter(b), IPC::getParameter(c), IPC::getParameter(d), IPC::getParameter(e), IPC::getParameter(f) ); handleReturnV(r); } inline void functionCallAsync(IPC::IPCClass* cl, const char* name) { IPC::IPCParameterI* r = cl->callFunction( name, true ); handleReturnV(r); } template <typename A> void functionCallAsync(IPC::IPCClass* cl, const char* name, A a) { IPC::IPCParameterI* r = cl->callFunction( name, true, IPC::getParameter(a)); handleReturnV(r); } template <typename A, typename B> void functionCallAsync(IPC::IPCClass* cl, const char* name, A a, B b) { IPC::IPCParameterI* r = cl->callFunction( name, true, IPC::getParameter(a), IPC::getParameter(b) ); handleReturnV(r); } template <typename A, typename B, typename C> void functionCallAsync(IPC::IPCClass* cl, const char* name, A a, B b, C c) { IPC::IPCParameterI* r = cl->callFunction( name, true, IPC::getParameter(a), IPC::getParameter(b), IPC::getParameter(c) ); handleReturnV(r); } template <typename A, typename B, typename C, typename D> void functionCallAsync(IPC::IPCClass* cl, const char* name, A a, B b, C c, D d) { IPC::IPCParameterI* r = cl->callFunction( name, true, IPC::getParameter(a), IPC::getParameter(b), IPC::getParameter(c), IPC::getParameter(d) ); handleReturnV(r); } template <typename A, typename B, typename C, typename D, typename E> void functionCallAsync(IPC::IPCClass* cl, const char* name, A a, B b, C c, D d, E e) { IPC::IPCParameterI* r = cl->callFunction( name, true, IPC::getParameter(a), IPC::getParameter(b), IPC::getParameter(c), IPC::getParameter(d), IPC::getParameter(e) ); handleReturnV(r); } template <typename A, typename B, typename C, typename D, typename E, typename F> void functionCallAsync(IPC::IPCClass* cl, const char* name, A a, B b, C c, D d, E e, F f) { IPC::IPCParameterI* r = cl->callFunction( name, true, IPC::getParameter(a), IPC::getParameter(b), IPC::getParameter(c), IPC::getParameter(d), IPC::getParameter(e), IPC::getParameter(f) ); handleReturnV(r); } 

additional code on request:

 template <typename R> R handleReturn(IPC::IPCParameterI* r) { if (r->getType() == PException::getTypeS()) { gcException gce((gcException*)r->getValue()); safe_delete(r); throw gce; } R temp = IPC::getParameterValue<R>(r, true); safe_delete(r); return temp; } inline void handleReturnV(IPC::IPCParameterI* r) { if (r->getType() == PException::getTypeS()) { gcException gce((gcException*)r->getValue()); safe_delete(r); throw gce; } safe_delete(r); return; } 
+4
source share
2 answers

Oh great! Let it be fun :)

Effectively, you can automatically calculate all of these patterns without varargs. This only requires preprocessor programming, so first consider Boost.Preprocessor .

First we need to develop a macro that takes care of the actual definition of the function:

 #define FUNCTION_CALL_IPC(z, n, data)\ IPC::getParameter( BOOST_PP_CAT(data, n) ) #define FUNCTION_CALL(z, n, data) \ template < \ class R \ BOOST_ENUM_TRAILING_PARAM(n, class Arg) \ > \ R functionCall(IPC::IPCClass* cl, const char* name \ BOOST_PP_ENUM_TRAILING_BINARY_PARAMS(n, Arg, const& arg) \ ) \ { \ IPC::IPCParameterI* r = cl->callFunction(name, false \ BOOST_PP_ENUM_TRAILING(n, FUNCTION_CALL_IPC, arg) \ ); \ return handleReturn<R>(r); \ } // From 0 to 9 arguments BOOST_PP_REPEAT(10, FUNCTION_CALL, ~) 

And voila.

Combined with Gman's void handling trick, you're all set!

+2
source

For variable arguments, you cannot do much. You can use Boost.Preprocessor to generate functions, but if that were an option, you could also use their Boost.Bind Library .

There is also a way to handle void functions as regular functions

You really can. Next: a-ok:

 void foo(void) { // sup } void bar(void) { return foo(); } void baz(void) { return bar(); } void lolwut(void) { return baz(); } 

He just does nothing, the reverse.


So what do you want:

 // snipping for conciseness, obviously this applies to all variants template <typename R> R functionCall(IPC::IPCClass* c, const char* name) { IPC::IPCParameterI* r = c->callFunction( name, false ); return handleReturn<R>(r); } template <typename R, typename A> // taking as const& to avoid copy R functionCall(IPC::IPCClass* cl, const char* name, const A& a) { IPC::IPCParameterI* r = cl->callFunction( name, false, IPC::getParameter(a)); return handleReturn<R>(r); } 

You just name it as usual, and when the return type is void put void in R Return will be considered return; .

Then the task becomes the handleReturn function. To execute the correct function, an if-statement command is required for compilation, based on R void or not. Here are the main features of the type (as such type requests are called) framework:

 // any constant-expression can be turned into a type // that can be instantiated, true and false generate // different types template <bool B> struct bool_type { static const bool value = B; }; // the two fundamental types that will be generated typedef bool_type<true> true_type; // the expression was true typedef bool_type<false> false_type; // the expression was false // mark functions that take a bool_type result... typedef const true_type& true_tag; // ...as "the result was true" typedef const false_type& false_tag; // ...or "the result was false" 

This is the core of the type system. Consider:

 void foo(true_tag); // B was true void foo(false_tag); // B was not true void foo(void) { static const bool B = true; foo( bool_type<B>() ); } 

Depending on whether B true or not, we will switch to another version of foo , either the true_tag variant or the false_tag variant. Make sure you understand this part before moving on.

Now we use specialized specialization to generate a type that inherits from bool_type and is either true_type or false_type depending on whether this trait is true. For us:

 template <typename T> // in general, T is not a void... struct is_void : bool_type<false> { typedef T type; }; template <> // ...but in this case it is struct is_void<void> : bool_type<true> { typedef void type; }; 

Now we can choose a function based on whether a particular type is void :

 void foo(true_tag); // R was void void foo(false_tag); // R was not void template <typename R> void foo(void) { // either inherits from true_type or false_type // and goes to the respective function foo( is_void<R>() ); } 

Or applies to our situation:

 // I put all my detail functions in a namespace called detail, // whether or not you do the same is up to you namespace detail { template <typename R> // not void variant R getReturn(IPC::IPCParameterI* r, false_tag) { R temp = IPC::getParameterValue<R>(r, true); safe_delete(r); return temp; } template <typename R> // void variant R getReturn(IPC::IPCParameterI*, true_tag) { // do nothing } } template <typename R> R handleReturn(IPC::IPCParameterI* r) { // applies to both if (r->getType() == PException::getTypeS()) { gcException gce((gcException*)r->getValue()); safe_delete(r); throw gce; } // but now route to the correct version return detail::getReturn<R>(r, is_void<R>()); } 

This code has minimal repetition regarding void return types.

+2
source

Source: https://habr.com/ru/post/1306327/


All Articles