241 votes

Surcharge de la macro sur le nombre d'arguments

J'ai deux macros FOO2 y FOO3 :

#define FOO2(x,y) ...
#define FOO3(x,y,z) ...

Je veux définir une nouvelle macro FOO comme suit :

#define FOO(x,y) FOO2(x,y)
#define FOO(x,y,z) FOO3(x,y,z)

Mais cela ne fonctionne pas car les macros ne surchargent pas sur le nombre d'arguments.

Sans modifier FOO2 y FOO3 existe-t-il un moyen de définir une macro FOO (en utilisant __VA_ARGS__ ou autre) pour obtenir le même effet d'envoi de FOO(x,y) a FOO2 y FOO(x,y,z) a FOO3 ?

2 votes

J'ai la forte impression que cette question a déjà été posée plusieurs fois... [mise à jour] par exemple aquí .

2 votes

@KerrekSB : Cela peut être lié, mais ce n'est certainement pas une copie.

0 votes

Non, peut-être pas celui-là, mais quelque chose comme ça arrive environ une fois par mois...

351voto

netcoder Points 31874

Simple comme bonjour :

#define GET_MACRO(_1,_2,_3,NAME,...) NAME
#define FOO(...) GET_MACRO(__VA_ARGS__, FOO3, FOO2)(__VA_ARGS__)

Donc si vous avez ces macros :

FOO(World, !)         # expands to FOO2(World, !)
FOO(foo,bar,baz)      # expands to FOO3(foo,bar,baz)

Si vous en voulez un quatrième :

#define GET_MACRO(_1,_2,_3,_4,NAME,...) NAME
#define FOO(...) GET_MACRO(__VA_ARGS__, FOO4, FOO3, FOO2)(__VA_ARGS__)

FOO(a,b,c,d)          # expeands to FOO4(a,b,c,d)

Naturellement, si vous définissez FOO2 , FOO3 y FOO4 les sorties seront remplacées par celles des macros définies.

0 votes

Est-ce possible, lorsqu'il existe un FOO0 supplémentaire qui prend 0 argument zéro ?

0 votes

Non. Il doit avoir au moins un argument.

7 votes

@Uroc327 Ajouter une macro à 0 argument à la liste est possible, voir ma réponse.

70voto

augurar Points 547

Pour compléter Réponse de Netcoder vous POUVEZ en fait le faire avec une macro à 0 argument, avec l'aide de l'outil GCC ##__VA_ARGS__ extension :

#define GET_MACRO(_0, _1, _2, NAME, ...) NAME
#define FOO(...) GET_MACRO(_0, ##__VA_ARGS__, FOO2, FOO1, FOO0)(__VA_ARGS__)

1 votes

Est-il possible de permettre FOO1 et FOO2 mais pas FOO0 sans faire #define FOO0 _Pragma("error FOO0 not allowed") ?

0 votes

FOO0 ne fonctionne pas en qt + mingw32, appel FOO0 invoquera le FOO1

0 votes

Très prometteur et simple. Mais ne fonctionne pas pour FOO0 avec -std=c++11...:-(

53voto

R1tschY Points 343

Voici une solution plus générale :

// get number of arguments with __NARG__
#define __NARG__(...)  __NARG_I_(__VA_ARGS__,__RSEQ_N())
#define __NARG_I_(...) __ARG_N(__VA_ARGS__)
#define __ARG_N( \
      _1, _2, _3, _4, _5, _6, _7, _8, _9,_10, \
     _11,_12,_13,_14,_15,_16,_17,_18,_19,_20, \
     _21,_22,_23,_24,_25,_26,_27,_28,_29,_30, \
     _31,_32,_33,_34,_35,_36,_37,_38,_39,_40, \
     _41,_42,_43,_44,_45,_46,_47,_48,_49,_50, \
     _51,_52,_53,_54,_55,_56,_57,_58,_59,_60, \
     _61,_62,_63,N,...) N
#define __RSEQ_N() \
     63,62,61,60,                   \
     59,58,57,56,55,54,53,52,51,50, \
     49,48,47,46,45,44,43,42,41,40, \
     39,38,37,36,35,34,33,32,31,30, \
     29,28,27,26,25,24,23,22,21,20, \
     19,18,17,16,15,14,13,12,11,10, \
     9,8,7,6,5,4,3,2,1,0

// general definition for any function name
#define _VFUNC_(name, n) name##n
#define _VFUNC(name, n) _VFUNC_(name, n)
#define VFUNC(func, ...) _VFUNC(func, __NARG__(__VA_ARGS__)) (__VA_ARGS__)

// definition for FOO
#define FOO(...) VFUNC(FOO, __VA_ARGS__)

Définissez vos fonctions :

#define FOO2(x, y) ((x) + (y))
#define FOO3(x, y, z) ((x) + (y) + (z))

// it also works with C functions:
int FOO4(int a, int b, int c, int d) { return a + b + c + d; }

Vous pouvez maintenant utiliser FOO avec 2, 3 et 4 arguments :

FOO(42, 42) // will use makro function FOO2
FOO(42, 42, 42) // will use makro function FOO3
FOO(42, 42, 42, 42) // will call FOO4 function

Limites

  • Seulement jusqu'à 63 arguments (mais extensible)
  • Fonction sans argument possible uniquement dans GCC

Idées

Utilisez-le pour les arguments par défaut :

#define func(...) VFUNC(func, __VA_ARGS__)
#define func2(a, b) func4(a, b, NULL, NULL)
#define func3(a, b, c) func4(a, b, c, NULL)

// real function:
int func4(int a, int b, void* c, void* d) { /* ... */ }

Utilisez-le pour les fonctions avec un nombre infini d'arguments possibles :

#define SUM(...) VFUNC(SUM, __VA_ARGS__)
#define SUM2(a, b) ((a) + (b))
#define SUM3(a, b, c) ((a) + (b) + (c))
#define SUM4(a, b, c) ((a) + (b) + (c) + (d))
// ...

PS : __NARG__ est copié de Laurent Deniau & Roland Illig ici : https://groups.google.com/group/comp.std.c/browse_thread/thread/77ee8c8f92e4a3fb/346fc464319b1ee5?pli=1

0 votes

0 votes

0 votes

La macro __NARG_I_ semble complètement inutile et superflu. Cela ne fait qu'ajouter une étape supplémentaire, et de la confusion. Je recommande de le supprimer entièrement et de définir simplement __NARG__ au lieu de : #define __NARG__(...) __ARG_N(__VA_ARGS__,__RSEQ_N()) .

21voto

lhumongous Points 471

J'étais en train de faire des recherches sur le sujet, et j'ai trouvé ceci aquí . L'auteur a ajouté le support des arguments par défaut pour les fonctions C via des macros.

Je vais essayer de résumer brièvement l'article. En gros, vous devez définir une macro qui peut compter les arguments. Cette macro renverra 2, 1, 0, ou tout autre intervalle d'arguments qu'elle peut supporter. Par exemple :

#define _ARG2(_0, _1, _2, ...) _2
#define NARG2(...) _ARG2(__VA_ARGS__, 2, 1, 0)

Pour cela, vous devez créer une autre macro qui prend un nombre variable d'arguments, compte les arguments et appelle la macro appropriée. J'ai pris votre exemple de macro et l'ai combiné avec l'exemple de l'article. J'ai fait en sorte que FOO1 appelle la fonction a() et que FOO2 appelle la fonction a avec l'argument b (évidemment, je suppose que c'est du C++ ici, mais vous pouvez changer la macro pour n'importe quoi).

#define FOO1(a) a();
#define FOO2(a,b) a(b);

#define _ARG2(_0, _1, _2, ...) _2
#define NARG2(...) _ARG2(__VA_ARGS__, 2, 1, 0)

#define _ONE_OR_TWO_ARGS_1(a) FOO1(a)
#define _ONE_OR_TWO_ARGS_2(a, b) FOO2(a,b)

#define __ONE_OR_TWO_ARGS(N, ...) _ONE_OR_TWO_ARGS_ ## N (__VA_ARGS__)
#define _ONE_OR_TWO_ARGS(N, ...) __ONE_OR_TWO_ARGS(N, __VA_ARGS__)

#define FOO(...) _ONE_OR_TWO_ARGS(NARG2(__VA_ARGS__), __VA_ARGS__)

Donc si vous avez

FOO(a)
FOO(a,b)

Le préprocesseur l'étend à

a();
a(b);

Je lirais certainement l'article dont j'ai donné le lien. Il est très instructif et il mentionne que NARG2 ne fonctionne pas sur les arguments vides. Il poursuit en disant aquí .

3voto

eyalm Points 1608

Vous pouvez peut-être utiliser cette macro pour compter le nombre d'arguments .

#define VA_NUM_ARGS(...) VA_NUM_ARGS_IMPL(__VA_ARGS__, 5,4,3,2,1)
#define VA_NUM_ARGS_IMPL(_1,_2,_3,_4,_5,N,...) N

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X