preprocesamiento - ¿Hay alguna forma de utilizar la stringificación del preprocesador de C++ en argumentos de macro variados?
ifdef (3)
Mi suposición es que la respuesta a esta pregunta es no, pero sería increíble si hubiera una manera. Para aclarar, supongamos que tengo la siguiente macro:
#define MY_VARIADIC_MACRO(X...) // Does some stuff here in the macro definition
Lo que me gustaría hacer es de alguna manera realizar una cadena en todas las variables de X antes de pasarlo a una función variadica; 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)
Probablemente no esté muy cerca de lo que quiere, pero algo como lo siguiente podría llevarlo allí:
#define MY_VARIADIC_MACRO(X) printf( "%s/n", #X )
Luego úsalo como el siguiente. Adjunte los parámetros en parens para que aparezca como un parámetro para la macro.
MY_VARIADIC_MACRO ((var1, var2, "cadena"));
A continuación, puede hacer que la macro llame a alguna función que elimine los pares externos o posiblemente analice la cadena dada.
Bien, no quise responder mi propia pregunta aquí, pero he encontrado una solución decente que es una especie de combinación de la 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 delimitadoras en la cadena. Aquí hay un ejemplo rápido:
#define MY_VARIADIC_MACRO(X...) printf(#X)
El uso de la macro anterior le muestra que todo el conjunto de argumentos pasados a la macro recibe una cadena.
Luego puede definir una función para tokenizar estos argumentos usando la coma de delimitación, obteniendo así el conjunto de cadenas tokenizadas utilizando la macro variadic:
#define MY_VARIADIC_MACRO(X...) tokenize_my_arguments(#X)
Entonces, en realidad, ya no existe la dependencia de que la macrovariable invoque 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.
* Cosas nuevas de Edit Follows *
Según el comentario de Tim, aquí están los detalles 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 un cálculo 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 al encontrar los tokens, aunque es probable que se sacrifique un poco de rendimiento. Sin embargo, para facilidad de mantenimiento, versatilidad y facilidad de implementación, esta 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;
}
Puede usar varias técnicas de macro recursivas para hacer cosas con macros variadas. Por ejemplo, puede definir una macro NUM_ARGS
que cuente la cantidad de argumentos en una macro variadica:
#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)
Luego, con eso, puede escribir una macro FOREACH
que amplíe 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)
:
Lo cual a su vez le permitirá definir su macro que codifica cada uno de sus argumentos:
#define STRINGIFY(X) #X
#define MY_VARIADIC_MACRO(...) FOREACH(STRINGIFY, (__VA_ARGS__))