Pregunta simple para la que no pude encontrar respuesta en la red. En macros de argumentos variados, ¿cómo encontrar el número de argumentos? Estoy de acuerdo con el preprocesador boost, si tiene la solución.
Si hace una diferencia, estoy tratando de convertir un número variable de argumentos macro para impulsar la secuencia, lista o matriz del preprocesador para su posterior reprocesamiento.
c++
c
c-preprocessor
variadic-macros
Anycorn
fuente
fuente
__typeof__
para que funcione al menos en algunos compiladoresRespuestas:
En realidad, esto depende del compilador y no es compatible con ningún estándar.
Aquí, sin embargo, tiene una implementación de macro que hace el recuento:
fuente
#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()
no devuelve 0. Las solucionesGET_ARG_COUNT()
&Y_TUPLE_SIZE()
funcionan.PP_NARG()
no devuelve 0" ... no es necesariamente un problema. Se puede decir quePP_NARG()
debería devolver 1 por la misma razónPP_NARG(,)
debería devolver 2. Detectar 0 puede ser útil en algunos casos, pero las soluciones parecen ser menos generales (requiriendo que el primer token sea pegable; lo cual puede o no estar bien dependiendo de para qué lo esté usando), o una implementación específica (como requerir el truco de gnu para quitar y pegar comas).Normalmente uso esta macro para encontrar varios parámetros:
Ejemplo completo:
Es un código C99 completamente válido. Sin embargo, tiene un inconveniente: no puede invocar la macro
SUM()
sin parámetros, pero GCC tiene una solución, consulte aquí .Entonces, en el caso de GCC, debe definir macros como este:
y funcionará incluso con la lista de parámetros vacía
fuente
sizeof(int) != sizeof(void *)
?{__VA_ARGS__}
aint[]
, es justoint[]
, independientemente del contenido real de__VA_ARGS__
##
es necesario en VS2017 ya que un vacío__VA_ARGS__
eliminará automáticamente cualquier coma anterior.Si está utilizando C ++ 11 y necesita el valor como una constante de tiempo de compilación de C ++, una solución muy elegante es esta:
Tenga en cuenta: el recuento ocurre completamente en tiempo de compilación, y el valor se puede usar siempre que se requiera un entero en tiempo de compilación, por ejemplo, como un parámetro de plantilla para std :: array.
fuente
sizeof((int[]){__VA_ARGS__})/sizeof(int)
sugerido anteriormente, funciona incluso cuando no se pueden lanzar todos los argumentosint
.#define NUM_ARGS(...) std::tuple_size<decltype(std::make_tuple(__VA_ARGS__))>::value
Para mayor comodidad, aquí hay una implementación que funciona para 0 a 70 argumentos y funciona en Visual Studio, GCC y Clang . Creo que funcionará en Visual Studio 2010 y versiones posteriores, pero solo lo he probado en VS2013.
fuente
__VA_ARGS__
" (que en C ++, es técnicamente una extensión del compilador (casi universal, estándar de facto ) hasta C ++ 20). La mayoría (¿todos?) Los compiladores permiten la longitud cero, pero se ahogan con la coma final si la lista está vacía (y se sobrecargan##
como un proto-__VA_OPT__
, para eliminar la coma en este caso); La versión de MSVC de la extensión simplemente no se ahoga con la coma (pero se ahoga con la sobrecargada##
). Compare MSVCunused, __VA_ARGS__
con no MSVC0, ## __VA_ARGS__
; ninguno es más correcto, el problema es que son diferentes.Hay algunas soluciones de C ++ 11 para encontrar la cantidad de argumentos en tiempo de compilación, pero me sorprende ver que nadie ha sugerido algo tan simple como:
Esto tampoco requiere la inclusión del
<tuple>
encabezado.fuente
VA_COUNT(&,^,%)
. Además, si está contando a través de una función, no veo ningún sentido en hacer una macro.esto funciona con 0 argumentos con gcc / llvm. [los enlaces son tontos]
Visual Studio parece estar ignorando el operador ## utilizado para consumir el argumento vacío. Probablemente puedas evitar eso con algo como
fuente
##__VA_ARGS__
comerse la coma antes de si__VA_ARGS__
está vacío es una extensión GCC. No es el comportamiento estándar.Con extensión msvc:
Funciona para 0 - 32 argumentos. Este límite se puede ampliar fácilmente.
EDITAR: Versión simplificada (funciona en VS2015 14.0.25431.01 Actualización 3 y gcc 7.4.0) hasta 100 argumentos para copiar y pegar:
fuente
Y_TUPLE_SIZE("Hello")
, por lo que es bastante inviable. Estoy de acuerdo con @osirisgothra.Supongo que cada argumento de VA_ARGS estará separado por comas. Si es así, creo que esto debería funcionar como una forma bastante limpia de hacer esto.
Funcionó para mí en godbolt para clang 4 y GCC 5.1. Esto se computará en tiempo de compilación, pero no se evaluará para el preprocesador. Entonces, si está tratando de hacer algo como hacer un FOR_EACH , esto no funcionará.
fuente
NUMARGS(hello, world = 2, ohmy42, !@#$%^&*()-+=)
!!! Sin','
embargoint count = NUMARGS( foo(1, 2) );
produce 2 en lugar de 1. godbolt.org/z/kpBuOmaquí una forma simple de contar 0 o más argumentos de VA_ARGS , mi ejemplo asume un máximo de 5 variables, pero puede agregar más si lo desea.
fuente
VA_ARGS_NUM
se usa con macro: si tengo#define TEST
(es decir, vacíoTEST
) yVA_ARGS_NUM(TEST)
no devuelve 0 (cero) cuando se usa en#if
:(Puede encadenar y contar tokens:
fuente
Boost Preprocessor en realidad tiene esto a partir de Boost 1.49, como
BOOST_PP_VARIADIC_SIZE(...)
. Funciona hasta el tamaño 64.Debajo del capó, es básicamente lo mismo que la respuesta de Kornel Kisielewicz .
fuente
__VA_OPT__
o las extensiones del compilador para##__VA_ARGS__
eliminar la coma anterior, por ejemplo: godbolt.org/z/X7OvnKHe encontrado respuestas aquí que todavía están incompletas.
La implementación portátil más cercana que he encontrado desde aquí es: preprocesador C ++ __VA_ARGS__ número de argumentos
Pero no funciona con los argumentos cero en el GCC sin al menos el
-std=gnu++11
parámetro de línea de comando.Así que decidí fusionar esta solución con eso: 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
fuente