Surcharge Macro Sur le nombre d'Arguments
j'ai deux macros FOO2
et 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 parce que les macros ne surchargent pas sur le nombre d'arguments.
sans modifier FOO2
et FOO3
, y a-t-il une façon de définir une macro FOO
(en utilisant __VA_ARGS__
ou autrement) pour obtenir le même effet d'expédition FOO(x,y)
à FOO2
, et FOO(x,y,z)
à FOO3
?
8 réponses
Simple comme:
#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 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
et FOO4
, la sortie sera remplacée par celles des macros définies.
pour ajouter à netcoder's answer , vous pouvez en fait le faire avec une macro à 0-argument, avec l'aide du GCC ##__VA_ARGS__
extension:
#define GET_MACRO(_0, _1, _2, NAME, ...) NAME
#define FOO(...) GET_MACRO(_0, ##__VA_ARGS__, FOO2, FOO1, FOO0)(__VA_ARGS__)
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; }
Maintenant vous pouvez 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
Limitations
- Seulement jusqu'à 63 arguments (mais extensible)
- fonction pour aucun argument seulement dans GCC possible""
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) { /* ... */ }
L'utiliser pour des fonctions avec un nombre infini possible d'arguments:
#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: https://groups.google.com/group/comp.std.c/browse_thread/thread/77ee8c8f92e4a3fb/346fc464319b1ee5?pli=1
je faisais des recherches moi-même, et je suis tombé sur ce ici . L'auteur a ajouté le support d'argument par défaut pour les fonctions C via des macros.
je vais essayer de résumer brièvement l'article. Fondamentalement, vous devez définir une macro qui peut compter les arguments. Cette macro retournera 2, 1, 0, ou n'importe quelle plage d'arguments qu'elle peut supporter. Par exemple:
#define _ARG2(_0, _1, _2, ...) _2
#define NARG2(...) _ARG2(__VA_ARGS__, 2, 1, 0)
avec ceci, 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 macro et l'ai combiné avec l'exemple de l'article. J'ai la fonction D'appel de FOO1 a() et la fonction D'appel de FOO2 a avec l'argument b (évidemment, je suppose C++ ici, mais vous pouvez changer la macro en 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 étend cela à
a();
a(b);
je voudrais certainement lu l'article que j'ai lié. C'est très instructif et il mentionne que NARG2 ne fonctionnera pas sur les arguments vides. Il poursuit ici .
Voici une version plus compacte de la réponse ci-dessus . Avec exemple.
#include <iostream>
using namespace std;
#define OVERLOADED_MACRO(M, ...) _OVR(M, _COUNT_ARGS(__VA_ARGS__)) (__VA_ARGS__)
#define _OVR(macroName, number_of_args) _OVR_EXPAND(macroName, number_of_args)
#define _OVR_EXPAND(macroName, number_of_args) macroName##number_of_args
#define _COUNT_ARGS(...) _ARG_PATTERN_MATCH(__VA_ARGS__, 9,8,7,6,5,4,3,2,1)
#define _ARG_PATTERN_MATCH(_1,_2,_3,_4,_5,_6,_7,_8,_9, N, ...) N
//Example:
#define ff(...) OVERLOADED_MACRO(ff, __VA_ARGS__)
#define ii(...) OVERLOADED_MACRO(ii, __VA_ARGS__)
#define ff3(c, a, b) for (int c = int(a); c < int(b); ++c)
#define ff2(c, b) ff3(c, 0, b)
#define ii2(a, b) ff3(i, a, b)
#define ii1(n) ii2(0, n)
int main() {
ff (counter, 3, 5)
cout << "counter = " << counter << endl;
ff (abc, 4)
cout << "abc = " << abc << endl;
ii (3)
cout << "i = " << i << endl;
ii (100, 103)
cout << "i = " << i << endl;
return 0;
}
Run:
User@Table 13:06:16 /c/T
$ g++ test_overloaded_macros.cpp
User@Table 13:16:26 /c/T
$ ./a.exe
counter = 3
counter = 4
abc = 0
abc = 1
abc = 2
abc = 3
i = 0
i = 1
i = 2
i = 100
i = 101
i = 102
notez qu'avoir à la fois _OVR
et _OVR_EXPAND
peut sembler redondant, mais il est nécessaire pour le préprocesseur d'étendre la partie _COUNT_ARGS(__VA_ARGS__)
, qui est autrement traité comme une chaîne.
peut-être Pouvez-vous 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
voici un extrait de la réponse D'Evgeni Sergeev. Celui-ci prend en charge zero argument surcharges ainsi!
j'ai testé ça avec GCC et MinGW. Il devrait fonctionner avec les anciennes et les nouvelles versions de C++. Notez que je ne le garantis pas pour MSVC... Mais avec quelques retouches, je suis sûr qu'il pourrait être fait pour travailler avec cela aussi.
j'ai aussi formaté ceci pour être collé dans un fichier d'en-tête (que j'ai appelé macroutil.h.) Si vous faites cela, vous pouvez simplement inclure cet en-tête peu importe ce dont vous avez besoin de la fonctionnalité, et ne regardez pas la méchanceté impliquée dans l'implémentation.
#ifndef MACROUTIL_H
#define MACROUTIL_H
//-----------------------------------------------------------------------------
// OVERLOADED_MACRO
//
// used to create other macros with overloaded argument lists
//
// Example Use:
// #define myMacro(...) OVERLOADED_MACRO( myMacro, __VA_ARGS__ )
// #define myMacro0() someFunc()
// #define myMacro1( arg1 ) someFunc( arg1 )
// #define myMacro2( arg1, arg2 ) someFunc( arg1, arg2 )
//
// myMacro();
// myMacro(1);
// myMacro(1,2);
//
// Note the numerical suffix on the macro names,
// which indicates the number of arguments.
// That is the REQUIRED naming convention for your macros.
//
//-----------------------------------------------------------------------------
// OVERLOADED_MACRO
// derived from: https://stackoverflow.com/questions/11761703/overloading-macro-on-number-of-arguments
// replaced use of _COUNT_ARGS macro with VA_NUM_ARGS defined below
// to support of zero argument overloads
#define OVERLOADED_MACRO(M, ...) _OVR(M, VA_NUM_ARGS(__VA_ARGS__)) (__VA_ARGS__)
#define _OVR(macroName, number_of_args) _OVR_EXPAND(macroName, number_of_args)
#define _OVR_EXPAND(macroName, number_of_args) macroName##number_of_args
//#define _COUNT_ARGS(...) _ARG_PATTERN_MATCH(__VA_ARGS__, 15,14,13,12,11,10,9,8,7,6,5,4,3,2,1)
#define _ARG_PATTERN_MATCH(_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13,_14,_15, N, ...) N
// VA_NUM_ARGS
// copied from comments section of:
// http://efesx.com/2010/07/17/variadic-macro-to-count-number-of-arguments/
// which itself was derived from:
// https://gustedt.wordpress.com/2010/06/08/detect-empty-macro-arguments/
#define _ARG16(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, ...) _15
#define HAS_COMMA(...) _ARG16(__VA_ARGS__, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0)
#define HAS_NO_COMMA(...) _ARG16(__VA_ARGS__, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1)
#define _TRIGGER_PARENTHESIS_(...) ,
#define HAS_ZERO_OR_ONE_ARGS(...) \
_HAS_ZERO_OR_ONE_ARGS( \
/* test if there is just one argument, eventually an empty one */ \
HAS_COMMA(__VA_ARGS__), \
/* test if _TRIGGER_PARENTHESIS_ together with the argument adds a comma */ \
HAS_COMMA(_TRIGGER_PARENTHESIS_ __VA_ARGS__), \
/* test if the argument together with a parenthesis adds a comma */ \
HAS_COMMA(__VA_ARGS__ (~)), \
/* test if placing it between _TRIGGER_PARENTHESIS_ and the parenthesis adds a comma */ \
HAS_COMMA(_TRIGGER_PARENTHESIS_ __VA_ARGS__ (~)) \
)
#define PASTE5(_0, _1, _2, _3, _4) _0 ## _1 ## _2 ## _3 ## _4
#define _HAS_ZERO_OR_ONE_ARGS(_0, _1, _2, _3) HAS_NO_COMMA(PASTE5(_IS_EMPTY_CASE_, _0, _1, _2, _3))
#define _IS_EMPTY_CASE_0001 ,
#define _VA0(...) HAS_ZERO_OR_ONE_ARGS(__VA_ARGS__)
#define _VA1(...) HAS_ZERO_OR_ONE_ARGS(__VA_ARGS__)
#define _VA2(...) 2
#define _VA3(...) 3
#define _VA4(...) 4
#define _VA5(...) 5
#define _VA6(...) 6
#define _VA7(...) 7
#define _VA8(...) 8
#define _VA9(...) 9
#define _VA10(...) 10
#define _VA11(...) 11
#define _VA12(...) 12
#define _VA13(...) 13
#define _VA14(...) 14
#define _VA15(...) 15
#define _VA16(...) 16
#define VA_NUM_ARGS(...) VA_NUM_ARGS_IMPL(__VA_ARGS__, PP_RSEQ_N(__VA_ARGS__) )
#define VA_NUM_ARGS_IMPL(...) VA_NUM_ARGS_N(__VA_ARGS__)
#define VA_NUM_ARGS_N( \
_1, _2, _3, _4, _5, _6, _7, _8, _9,_10, \
_11,_12,_13,_14,_15,_16,N,...) N
#define PP_RSEQ_N(...) \
_VA16(__VA_ARGS__),_VA15(__VA_ARGS__),_VA14(__VA_ARGS__),_VA13(__VA_ARGS__), \
_VA12(__VA_ARGS__),_VA11(__VA_ARGS__),_VA10(__VA_ARGS__), _VA9(__VA_ARGS__), \
_VA8(__VA_ARGS__),_VA7(__VA_ARGS__),_VA6(__VA_ARGS__),_VA5(__VA_ARGS__), \
_VA4(__VA_ARGS__),_VA3(__VA_ARGS__),_VA2(__VA_ARGS__),_VA1(__VA_ARGS__), \
_VA0(__VA_ARGS__)
//-----------------------------------------------------------------------------
#endif // MACROUTIL_H
cela semble bien fonctionner sur GCC, Clang et MSVC. C'est une version nettoyée de certaines des réponses ici
#define __BUGFX(x) x
#define __NARG2(...) __BUGFX(__NARG1(__VA_ARGS__,__RSEQN()))
#define __NARG1(...) __BUGFX(__ARGSN(__VA_ARGS__))
#define __ARGSN(_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,N,...) N
#define __RSEQN() 10,9,8,7,6,5,4,3,2,1,0
#define __FUNC2(name,n) name ## n
#define __FUNC1(name,n) __FUNC2(name,n)
#define GET_MACRO(func,...) __FUNC1(func,__BUGFX(__NARG2(__VA_ARGS__))) (__VA_ARGS__)