2010-04-08 4 views
4

J'ai un tas de gabarits qui sont utilisés pour rpc et je me demandais s'il y avait un moyen de les simplifier car il se répète automatiquement. Je sais que varags pour les templates vient dans la prochaine norme mais pouvez-vous faire des valeurs par défaut pour les templates?simplifier les gabarits

Existe-t-il également un moyen de gérer les fonctions de retour vides comme des fonctions normales? Atm Je dois les séparer et les traiter comme deux choses différentes chaque fois en raison de modèles ne ramassant pas vide comme 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); 
} 

code supplémentaire comme demandé:

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; 
} 
+0

Sans rapport avec votre question, mais qu'est-ce que 'safe_delete'? – GManNickG

+0

juste un moyen de s'assurer que je supprime un pointeur et le définir à NULL. A également des surcharges pour différents types comme char * et vecteurs – Lodle

+0

D'accord. :) Tant que vous ne vérifiez pas null avant de supprimer I "m heureux.: P (Suppression de null est un no-op, totalement sûr.) – GManNickG

Répondre

2

Oh génial! Amusons-nous :)

Il est effectivement possible de calculer automatiquement tous ces modèles sans varargs. Il nécessite seulement la programmation du préprocesseur, alors regardons d'abord Boost.Preprocessor.

D'abord, nous devons mettre au point une macro qui prendra soin de la définition de la fonction réelle:

#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, ~) 

Et le tour est joué.

Combiné avec l'astuce de Gman pour gérer void, vous êtes tous ensemble!

+0

Là vous allez encore avec vos manigances de préprocesseur. :) – GManNickG

+0

Wow, c'est fou, sauf que personne ne serait en mesure de le changer. Souhaite que je puisse attribuer deux meilleures réponses, mais mal vous Mat comme vous avez moins xp. – Lodle

+0

'@ GMan': Je dois admettre que j'aime jouer avec le préprocesseur :)' @ Lodle': accepter tout ce que vous voulez, je me fous de xp: p En ce qui concerne la maintenance, j'avoue que ça pourrait être un peu gênant mais le vrai bummer est le débogage;) ne pas oublier l'option '-E' sur' gcc' pour obtenir la sortie du préprocesseur! –

2

Pour arguments variables, il n'y a pas grand-chose que vous pouvez faire. Vous pouvez utiliser Boost.Preprocessor pour générer les fonctions, mais si c'était une option, vous pouvez aussi bien utiliser leur bibliothèque Boost.Bind.

est là aussi une façon de gérer les fonctions vides comme fonctions normales

Vous pouvez en fait. Ce qui suit est a-ok:

void foo(void) 
{ 
    // sup 
} 

void bar(void) 
{ 
    return foo(); 
} 

void baz(void) 
{ 
    return bar(); 
} 

void lolwut(void) 
{ 
    return baz(); 
} 

Cela ne fait rien, en retour.


donc ce que vous voulez est:

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

Vous appelez juste comme d'habitude, et quand le type de retour est mis voidvoid comme R. Les retours seront traités comme return;.

Le problème devient alors la fonction handleReturn. Vous avez besoin d'une if-instruction à la compilation pour router vers la bonne fonction selon que R est void ou non. Voici un type-traits de base (comme les requêtes sur les types sont appelés) Cadre:

// 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" 

C'est le cœur même d'un système de type-traits. Tenir compte:

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

Selon que B est vrai ou non, nous acheminera vers une autre version de foo, soit la variante true_tag, ou la variante false_tag. Assurez-vous de bien comprendre cette partie avant de continuer.

Nous utilisons maintenant la spécialisation de modèle pour générer un type qui hérite de bool_type, et est soit un true_type ou false_type selon si ce trait est vrai.Pour nous:

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

Maintenant, nous pouvons choisir une fonction basée au large ou non un certain type est 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>()); 
} 

ou appliqué à notre 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>()); 
} 

Ce code a répétition minimale dans les préoccupations à void types de retour.

+0

Je ne vois pas comment votre exemple correspond au problème du nombre arbitraire d'arguments +1 Pour Boost.Bind si. – Basilevs

+0

Je parlais du type de retour car void est difficile à utiliser dans le modèle normal – Lodle

+0

@Basilevs: Je traitais de la question "Il existe aussi un moyen de gérer les fonctions vides comme des fonctions normales." Mais j'ai tout abordé maintenant, – GManNickG