¿Cuánto se puede hacer con macros (de orden superior)?
-
06-07-2019 - |
Pregunta
¿Es " seguro " dar nombres de macros como argumentos a otras macros para simular funciones de orden superior?
I.e. ¿Dónde debo mirar para no pegarme un tiro en el pie?
Aquí hay algunos fragmentos:
#define foreach_even(ii, instr) for(int ii = 0; ii < 100; ii += 2) { instr; }
#define foreach_odd(ii, instr) for(int ii = 1; ii < 100; ii += 2) { instr; }
#define sum(foreach_loop, accu) \
foreach_loop(ii, {accu += ii});
int acc = 0;
sum(foreach_even, acc);
sum(foreach_odd, acc);
¿Qué pasa con la aplicación parcial, puedo hacer eso? :
#define foreach(ii, start, end, step, instr) \
for(int ii = start; ii < end; ii += step) { instr; }
#define foreach_even(ii, instr) foreach(ii, 0, 100, instr)
#define foreach_odd(ii, instr) foreach(ii, 1, 100, instr)
#define sum(foreach_loop, accu) \
foreach_loop(ii, {accu += ii});
int acc = 0;
sum(foreach_even, acc);
sum(foreach_odd, acc);
¿Y puedo definir una macro dentro de una macro?
#define apply_first(new_macro, macro, arg) #define new_macro(x) macro(arg,x)
Solución
Si está interesado en utilizar el preprocesador tanto como sea posible, puede intentar boost.preprocessor .
Pero tenga en cuenta que no es seguro hacerlo. Las comas, por ejemplo, causan una gran cantidad de problemas al usar preprocesadores. No olvide que los preprocesadores no entienden (o incluso tratan de entender) ninguno de los códigos que generan.
Mi consejo básico es "no lo hagas" o "hazlo con la mayor cautela posible".
Otros consejos
He implementado un pequeño marco de prueba de unidad podrida completamente en preprocesador c. Varias docenas de macros, un montón de macros es un argumento para otro tipo de macro.
Este tipo de cosas es no " seguro " en el mejor sentido de la palabra. Hay formas sutiles y muy poderosas de dispararte en el pie. El proyecto de prueba de la unidad es un juguete que se salió de control.
No sé si puede anidar definiciones de macro. Lo dudo, pero lo intentaré ... a gcc no le gusta y responde con
nested_macro.cc:8: error: parásito '#' en el programa
nested_macro.cc:3: error: constructor esperado, destructor o conversión de tipo antes de '(' token
nested_macro.cc:3: error: declaración esperada antes del token '}'
Autoenchufe : si está interesado, puede encontrar el marco de prueba de unidad en https://sourceforge.net/projects/dut/