2011-05-10 41 views
10

Supongo que la respuesta a esta pregunta es no, pero sería increíble si hubiera alguna manera. Para aclarar, supongamos que tengo la siguiente macro:¿Hay alguna manera de utilizar la stringificación del preprocesador de C++ en argumentos de macro variados?

#define MY_VARIADIC_MACRO(X...) // Does some stuff here in the macro definition 

Lo que me gustaría hacer es realizar alguna manera stringification sobre todas las variables de X antes de pasarlo a una función variadic; la palabra clave aquí es antes. Me doy cuenta de que no hay forma de acceder realmente a los argumentos individuales desde dentro de la definición de la macro, pero ¿hay alguna forma de codificar todos los argumentos, tal vez con algo como lo siguiente?

#define MY_VARIADIC_MACRO(X...) some_variadic_function("some string", #X) 

Respuesta

8

Bien, no quise responder mi propia pregunta aquí, pero he encontrado una solución decente que es una especie de combinación de respuesta de Mark Wilkins y el ejemplo que di en la pregunta.

Es posible codificar todo el conjunto varío conjunto, que luego incluye las comillas de delimitación en la cadena. Aquí hay un ejemplo rápido:

#define MY_VARIADIC_MACRO(X...) printf(#X) 

El uso de la macro anterior se demuestra que todo el conjunto de argumentos que se pasan a la macro se Stringified.

A continuación, se puede definir una función para tokenize estos argumentos utilizando la coma delimitadora, consiguiendo con ello el conjunto de cadenas tokenizados mediante el uso de la macro variadic:

#define MY_VARIADIC_MACRO(X...) tokenize_my_arguments(#X) 

Luego está realmente ya no la dependencia de tener el Una macro variadica llama a una función variadica y puedo iterar muy bien a través de mi matriz de cadenas C constantes en lugar de iterar a través de va_arg.

* Nueva materia de Editar Sigue el comentario de *

por Tim, aquí está el detalle de la solución. Por favor, perdona cualquier error ya que fue hecho de forma apresurada y tuve que realizar un puerto a partir de lo que estoy trabajando. Además, no está destinado a ser una solución de copiar/pegar ya que solo muestra la cadena de los argumentos para demostrar POC, pero debería ser suficiente para demostrar la funcionalidad.

Aunque esta solución requiere algunos cálculos de tiempo de ejecución, las macros variadas muchas veces llaman a funciones variadas y requieren iteración a través de va_args, por lo que la iteración tiene lugar para encontrar los tokens, aunque probablemente se sacrifique un poco de rendimiento.Sin embargo, para el mantenimiento, versatilidad y facilidad de implementación, esto parece ser la mejor opción en este momento:

#define VARIADIC_STRINGIFY(_ARGUMENTS_TO_STRINGIFY...) Variadic_Stringification_Without_Variadic_Function(#_ARGUMENTS_TO_STRINGIFY) 

void Variadic_Stringification_Without_Variadic_Function (const char* _stringified_arguments) 
{ 
    strcpy(converted_arguments, _stringified_arguments); 

    for(char* token = strtok(converted_arguments, ","); token != 0x0; token = strtok(0x0, ",")) 
     std::cout << token << std::endl; 
} 
+0

Además, otra buena característica de esto es que puedo encontrar fácilmente la cantidad de argumentos sin tener que pasar algún tipo de información a través de la macro para determinar dónde terminan los argumentos en la lista. – Hazok

+0

Interesante, pero antes de marcar esto como una solución, publique su código real que lo resolvió. Estoy seguro de que será útil para otros. – Tim

+0

@Tim Will do, ya he probado un caso simple y lo convertiré en un mejor ejemplo ... tengo algunos plazos y lo publicaré mañana (5/11/2011) o al día siguiente. – Hazok

2

Esta es, probablemente, no es muy cercano a lo que usted está deseando, pero algo como lo siguiente podría llegar hasta allí:

#define MY_VARIADIC_MACRO(X) printf("%s\n", #X) 

A continuación, utilizarlo como la siguiente. Adjunte los parámetros en parens para que aparezca como un parámetro para la macro.

MY_VARIADIC_MACRO ((var1, var2, "cadena"));

Puede hacer que la macro llame a alguna función que elimine los pares externos o posiblemente analice la cadena dada.

+0

eso es casi allí, pero la idea es aliviar el t él necesita incluir el paréntesis ... maldito retorno agrega el comentario rápido, necesita recordar el retorno-cambio. Creo que lo anterior está muy cerca de una solución para la que estoy trabajando. Votaré esta respuesta porque ya casi está allí, pero no puedo marcarla como la respuesta principal, ya que no satisface completamente los requisitos. – Hazok

+0

@Zach: lo adiviné. Me encantaría ver cómo se podría hacer eso. Entiendo que no es posible, pero me gustaría que se me muestre de manera diferente. –

+0

He publicado la respuesta anterior con la que me voy a ir, bastante entusiasmado con ella, resuelve MUCHOS de los problemas que estaba enfrentando. – Hazok

18

se pueden utilizar diversas técnicas recursivas macro para hacer cosas con las macros variadic. Por ejemplo, puede definir una macro NUM_ARGS que cuenta el número de argumentos a una macro variadic:

#define _NUM_ARGS(X100, X99, X98, X97, X96, X95, X94, X93, X92, X91, X90, X89, X88, X87, X86, X85, X84, X83, X82, X81, X80, X79, X78, X77, X76, X75, X74, X73, X72, X71, X70, X69, X68, X67, X66, X65, X64, X63, X62, X61, X60, X59, X58, X57, X56, X55, X54, X53, X52, X51, X50, X49, X48, X47, X46, X45, X44, X43, X42, X41, X40, X39, X38, X37, X36, X35, X34, X33, X32, X31, X30, X29, X28, X27, X26, X25, X24, X23, X22, X21, X20, X19, X18, X17, X16, X15, X14, X13, X12, X11, X10, X9, X8, X7, X6, X5, X4, X3, X2, X1, N, ...) N 

#define NUM_ARGS(...) _NUM_ARGS(__VA_ARGS__, 100, 99, 98, 97, 96, 95, 94, 93, 92, 91, 90, 89, 88, 87, 86, 85, 84, 83, 82, 81, 80, 79, 78, 77, 76, 75, 74, 73, 72, 71, 70, 69, 68, 67, 66, 65, 64, 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) 

Entonces, con eso, se puede escribir una macro FOREACH que se expande otra macro para cada elemento de una lista:

#define EXPAND(X)  X 
#define FIRSTARG(X, ...) (X) 
#define RESTARGS(X, ...) (__VA_ARGS__) 
#define FOREACH(MACRO, LIST) FOREACH_(NUM_ARGS LIST, MACRO, LIST) 
#define FOREACH_(N, M, LIST) FOREACH__(N, M, LIST) 
#define FOREACH__(N, M, LIST) FOREACH_##N(M, LIST) 
#define FOREACH_1(M, LIST) M LIST 
#define FOREACH_2(M, LIST) EXPAND(M FIRSTARG LIST) FOREACH_1(M, RESTARGS LIST) 
#define FOREACH_3(M, LIST) EXPAND(M FIRSTARG LIST) FOREACH_2(M, RESTARGS LIST) 
     : 

que a su vez permitirá definir la macro que stringifies cada uno de sus argumentos:

#define STRINGIFY(X) #X 
#define MY_VARIADIC_MACRO(...) FOREACH(STRINGIFY, (__VA_ARGS__)) 
+0

Conozco esas técnicas recursivas, pero como se ven desde arriba son tediosas y también tienen la desafortunada restricción de que estás limitado al número de argumentos que cuentas en tiempo de compilación. Pronto actualizaré mi respuesta con los detalles de esa solución que no es tan tediosa de implementar y no está restringida a un máximo predefinido que es más fácil de mantener. Puede ser la mejor solución para todos los casos, pero para lo que necesito es una mejor respuesta que la anterior. ¡Gracias por la entrada! – Hazok

Cuestiones relacionadas