Question simple à laquelle je n'ai pas trouvé de réponse sur le net. Dans les macros d'arguments variadiques, comment trouver le nombre d'arguments? Je suis d'accord avec le préprocesseur boost, s'il a la solution.
Si cela fait une différence, j'essaie de convertir un nombre variable d'arguments de macro pour stimuler la séquence, la liste ou le tableau du préprocesseur pour un retraitement ultérieur.
c++
c
c-preprocessor
variadic-macros
Anycorn
la source
la source
__typeof__
pour le faire fonctionner au moins sur certains compilateursRéponses:
Cela dépend en fait du compilateur et n'est pris en charge par aucun standard.
Ici, cependant, vous avez une implémentation de macro qui fait le décompte:
la source
#define EXPAND(x) x
#define PP_ARG_N(_1,_2,_3,_4,_5,_6,_7,_8,_9,N,...) N
#define PP_NARG(...) EXPAND(PP_ARG_N(__VA_ARGS__, 9,8,7,6,5,4,3,2,1,0))
`` ``PP_NARG()
ne parvient pas à renvoyer 0. Les solutionsGET_ARG_COUNT()
&Y_TUPLE_SIZE()
fonctionnent.PP_NARG()
ne retourne pas 0" ... n'est pas nécessairement un problème. On peut dire quePP_NARG()
devrait renvoyer 1 pour la même raisonPP_NARG(,)
devrait retourner 2. La détection de 0 peut en effet être pratique dans certains cas, mais les solutions semblent soit être moins générales (exigeant que ce premier jeton soit collable; ce qui peut ou non être correct selon l'utilisation que vous en faites), ou spécifique à l'implémentation (comme exiger l'astuce de suppression de virgule-coller de gnu).J'utilise généralement cette macro pour trouver un certain nombre de paramètres:
Exemple complet:
C'est un code C99 entièrement valide. Il a un inconvénient, cependant - vous ne pouvez pas invoquer la macro
SUM()
sans paramètres, mais GCC a une solution - voir ici .Donc, dans le cas de GCC, vous devez définir des macros comme ceci:
et cela fonctionnera même avec une liste de paramètres vide
la source
sizeof(int) != sizeof(void *)
?{__VA_ARGS__}
surint[]
, c'est justeint[]
, quel que soit le contenu réel de__VA_ARGS__
##
n'est pas nécessaire dans VS2017 car un vide__VA_ARGS__
supprimera automatiquement toute virgule précédente.Si vous utilisez C ++ 11 et que vous avez besoin de la valeur en tant que constante de compilation C ++, une solution très élégante est la suivante:
Remarque: le comptage se produit entièrement au moment de la compilation, et la valeur peut être utilisée chaque fois qu'un entier au moment de la compilation est requis, par exemple comme paramètre de modèle pour std :: array.
la source
sizeof((int[]){__VA_ARGS__})/sizeof(int)
suggéré ci-dessus, cela fonctionne même lorsque les arguments ne peuvent pas tous être exprimésint
.#define NUM_ARGS(...) std::tuple_size<decltype(std::make_tuple(__VA_ARGS__))>::value
Pour plus de commodité, voici une implémentation qui fonctionne pour 0 à 70 arguments et fonctionne dans Visual Studio, GCC et Clang . Je pense que cela fonctionnera dans Visual Studio 2010 et versions ultérieures, mais je ne l'ai testé que dans VS2013.
la source
__VA_ARGS__
" (qui en C ++, est techniquement une extension de compilateur (presque universelle, de facto standard) jusqu'à C ++ 20). La plupart (tous?) Des compilateurs autorisent une longueur nulle, mais s'étouffent avec la virgule de fin si la liste est vide (et surcharge en##
tant que proto-__VA_OPT__
, pour supprimer la virgule dans ce cas); La version de MSVC de l'extension ne fonctionne tout simplement pas étouffer la virgule (mais va étouffer la surcharge##
). Comparez MSVCunused, __VA_ARGS__
à non MSVC0, ## __VA_ARGS__
; ni l'un ni l'autre n'est plus correct, le problème est qu'ils sont différents.Il existe des solutions C ++ 11 pour trouver le nombre d'arguments au moment de la compilation, mais je suis surpris de voir que personne n'a suggéré quelque chose d'aussi simple que:
Cela ne nécessite pas non plus l'inclusion de l'en-
<tuple>
tête.la source
VA_COUNT(&,^,%)
. De plus, si vous comptez via une fonction, je ne vois aucun sens à créer une macro.cela fonctionne avec 0 argument avec gcc / llvm. [les liens sont stupides]
Visual Studio semble ignorer l'opérateur ## utilisé pour consommer l'argument vide. Vous pouvez probablement contourner cela avec quelque chose comme
la source
##__VA_ARGS__
manger la virgule avant si__VA_ARGS__
est vide est une extension GCC. Ce n'est pas le comportement standard.Avec l'extension msvc:
Fonctionne pour 0 à 32 arguments. Cette limite peut être facilement étendue.
EDIT: Version simplifiée (fonctionne dans VS2015 14.0.25431.01 Update 3 & gcc 7.4.0) jusqu'à 100 arguments à copier et coller:
la source
Y_TUPLE_SIZE("Hello")
, ce qui la rend tout à fait irréalisable. Je suis d'accord avec @osirisgothra.Je suppose que chaque argument de VA_ARGS sera séparé par des virgules. Si c'est le cas, je pense que cela devrait fonctionner comme un moyen assez propre de le faire.
A travaillé pour moi sur godbolt pour clang 4 et GCC 5.1. Cela calculera au moment de la compilation, mais n'évaluera pas pour le préprocesseur. Donc, si vous essayez de faire quelque chose comme créer un FOR_EACH , cela ne fonctionnera pas.
la source
NUMARGS(hello, world = 2, ohmy42, !@#$%^&*()-+=)
!!! Chaque chaîne d'argument ne peut pas avoir d'autres symboles comme','
siint count = NUMARGS( foo(1, 2) );
produit 2 au lieu de 1. godbolt.org/z/kpBuOmici un moyen simple de compter 0 ou plus d'arguments de VA_ARGS , mon exemple suppose un maximum de 5 variables, mais vous pouvez en ajouter plus si vous le souhaitez.
la source
VA_ARGS_NUM
est utilisée avec la macro: si j'ai#define TEST
(c'est-à-dire videTEST
) etVA_ARGS_NUM(TEST)
ne renvoie pas 0 (zéro) lorsqu'elle est utilisée dans#if
:(Vous pouvez enchaîner et compter les jetons:
la source
Boost Preprocessor a en fait ceci à partir de Boost 1.49, car
BOOST_PP_VARIADIC_SIZE(...)
. Cela fonctionne jusqu'à la taille 64.Sous le capot, c'est fondamentalement la même chose que la réponse de Kornel Kisielewicz .
la source
__VA_OPT__
ou les extensions du compilateur pour##__VA_ARGS__
supprimer la virgule précédente, par exemple: godbolt.org/z/X7OvnKJ'ai trouvé ici que les réponses sont encore incomplètes.
L'implémentation portable la plus proche que j'ai trouvée à partir d'ici est: préprocesseur C ++ __VA_ARGS__ nombre d'arguments
Mais cela ne fonctionne pas avec les arguments zéro dans le GCC sans au moins
-std=gnu++11
paramètre de ligne de commande.J'ai donc décidé de fusionner cette solution avec celle-ci: https://gustedt.wordpress.com/2010/06/08/detect-empty-macro-arguments/
https://godbolt.org/z/3idaKd
c++11
,msvc 2015
,gcc 4.7.1
,clang 3.0
la source