2010-09-08 3 views
2

Je souhaite créer des macros qui vont insérer un paramètre dans un appel de fonction. Par exemple, j'ai la fonction Action() déclarée ci-dessous. L'action prend comme entrée une énumération pour le numéro d'état et une chaîne formatée avec des arguments facultatifs pour la chaîne.Comment ajouter un paramètre à un appel de fonction de chaîne formatée via une fonction #define

Je veux définir des macros afin qu'au lieu d'appeler Action(ActionState1, "someText %d", &arg) avec ActionState1 pour le paramètre d'état, je peux simplement appeler State1("someText %d", &arg) à la place. De cette façon la macro collerait dans le ActionState1 pour l'état param pour moi. Je pense à quelque chose comme le suivant:

#define State1(formatedString, ...) Action(ActionState1, formatedString, ...) 
#define State2(formatedString, ...) Action(ActionState2, formatedString, ...) 
#define State3(formatedString, ...) Action(ActionState3, formatedString, ...) 

enum { 
    ActionState1, 
    ActionState2, 
    ActionState3 
} 

static void Action(State state, String formatedString, ...); 

Est-ce que quelqu'un sait quel serait le bon format?

+0

Tout simplement parce que vous * pouvez * le faire, cela ne signifie pas que vous * devriez *. Pensez à passer un 'enum' comme premier paramètre à' Action', ou factoriser 'Action' dans plusieurs fonctions. – Seth

+0

Enum est le premier paramètre à Action, je ne l'avais pas montré dans mon exemple (je l'ai mis à jour maintenant). –

Répondre

2

Je crois que __VA_ARGS__ est ce que vous cherchez:

#define State1(formattedString, ...) Action(1, (formattedString), __VA_ARGS__) 
. 
. 
. 

Ceci est une caractéristique de C99, et Wikipedia claims qu'ils ne font pas partie d'une norme C++ officielle (Je note cela parce que vous utilisez le C++ tag), mais une extension assez populaire. Il y a de bonnes discussions à this question.

+0

OP voulait: _le macro resterait dans l'état = 1 bit pour moi_.Je ne vois pas comment '__VA_ARGS__' peut aider. À mon humble avis, les ellipses ne doivent pas être prises pour représenter une fonction variadique «Action». Mais j'ai peut-être tort. – dirkgently

+0

Merci, c'est exactement ce que je voulais –

+0

Je pense que «Action» doit être variée parce que la question de l'OP a une chaîne de format dans l'exemple. –

2

Non, cela ne peut pas être fait en utilisant le préprocesseur. Le préprocesseur vous permet de chaîner des entités mais pas de manière inversée. Pour ce que vous voulez, vous devrez diviser State1 en deux composants State et 1 (ce dernier étant plus important) et procéder à l'appel.

Cependant, la question la plus importante est pourquoi voudriez-vous faire cela? Vous enregistrez à peine toute frappe par une telle transformation ou gagnez en lisibilité.

Vous pouvez obtenir quelque chose à proximité en utilisant des modèles bien:

template <size_t N> 
T State(string fmt, ...) { return Action(N, fmt, ...); } // assume T Action(size_t, ...); 

et utiliser ce qui précède que:

State<1>(fmtStr, ...); 
State<2>(fmtStr2, ...); 

Mais encore une fois, il n'y a guère de gain syntaxique ici OMI.

+0

Ce que j'ai omis dans mon exemple est que les 1, 2, 3 sont représentés par des variables enum qui deviennent extrêmement longues, un peu comme ClassA :: EnumA :: State1, auquel cas quelque chose comme State (string fmt, ...) serait un peu compliqué à taper par rapport à State1 (string fmt, ...), mais si vous avez une meilleure suggestion je suis tout ouïe :) Merci pour l'entrée –

0

Pourquoi voulez-vous créer une telle chose? En C++ Préférez utiliser des opérateurs de streaming ou similaire en utilisant varargs car il gagne entre autres la sécurité de type.

Je ne crois pas qu'il existe un moyen de faire ce que vous voulez dans les macros de préprocesseur C++. Si vous aviez une version va_list d'Action, vous pourriez être en mesure de sortir avec quelque chose comme ce qui suit, mais je semble rappeler que le paramètre devant le ... doit être POD - malheureusement, une recherche rapide ne peut pas confirmer ou infirmer cela.

#include <cstdarg> 
inline void State1(String formatedString, ...) 
{ 
    va_list args; 
    va_start(args, formatedString); 
    Action(1, formatedString, args); 
    va_end(args); 
} 
+0

J'ai les trucs va_list dans Action. J'ai juste besoin de lui passer le paramètre d'état. Connaissez-vous un meilleur moyen d'y parvenir sans définir une nouvelle fonction pour chaque instance d'État? Je le fais de cette façon parce que j'ai 7 états différents –

Questions connexes