salida - ¿Puedo agregar a una macro de preprocesador?
funcion preprocesador en c++ (3)
No estoy seguro de si esto ayuda, pero puedes hacer vari arg macros. El Sr. Conrad del proyecto x264 ama el abuso de preprocesadores. Si suenan como si pudieran ayudarlo, puede encontrar más información aquí.
¿Hay alguna forma en C estándar o con extensiones de GNU para agregar cosas a una definición de macro? Por ejemplo , dada una macro definida como
#define List foo bar
puedo agregar bas
para que se expanda como si lo hubiera definido
#define List foo bar bas
?
Esperaba poder hacer algo como esto:
#define List foo bar bas
#define List_ Expand(List)
#undef List
#define List Expand(List_) quux
pero no puedo entender cómo definir la macro Expand()
para que haga lo que quiero.
Motivación: estoy jugando con sindicatos discriminados / etiquetados en esta línea:
struct quux_foo { int x; };
struct quux_bar { char *s; };
struct quux_bas { void *p; };
enum quux_type {quux_foo, quux_bar, quux_bas};
struct quux {
enum quux_type type;
union {
struct quux_foo foo;
struct quux_bar bar;
struct quux_bas bas;
} t;
};
Me imagino que este es un buen lugar para el X-macro. Si defino una macro
#define quux_table X(foo) X(bar) X(bas)
la enumeración y la estructura se pueden definir así y nunca perderse de sincronización:
#define X(t) quux_ ## t,
enum quux_type {quux_table};
#undef X
#define X(t) struct quux_ ## t t;
struct quux {
enum quux_type type;
union {quux_table} t;
};
#undef X
Por supuesto, las estructuras quux_*
pueden perder su sincronización, por lo que me gustaría hacer algo como esto, solo legalmente:
struct quux_foo { int x; };
#define quux_table quux_table X(foo)
struct quux_bar { char *s; };
#define quux_table quux_table X(bar)
struct quux_bas { void *p; };
#define quux_table quux_table X(bas)
(Bueno, lo que realmente quiero ser capaz de hacer es algo así como
member_struct(quux, foo) { int x; };
pero soy consciente de que las macros no se pueden (re) definir desde macros).
De todos modos, ese es mi ejemplo motivador. ¿Hay alguna manera de lograr esto?
Los ejemplos de Boost.Preprocessor están bien, si puede mostrarme cómo hacer que la técnica X-macro funcione con esa biblioteca.
Efectivamente, no.
Las macros son evaluadas perezosamente. Cuando #define List_ Expand(List)
, su lista de reemplazo es la secuencia de cuatro tokens Expand
, (
, List
, y )
. No hay ninguna forma de expandir una macro en una lista de reemplazo.
Todas las macro sustituciones tienen lugar cuando se invoca una macro.
Recomiendo mirar usando la biblioteca Boost.Preprocessor para la generación automática de código. Es un poco de trabajo, pero puedes lograr cosas bastante impresionantes usándolo. Debería ser totalmente compatible con C.
¡Hay una manera!
Usando la nueva palabra clave _Pragma esto se puede lograr en gcc (aunque no con msvc)
Si saca una macro dentro de su propia definición, retrasará su expansión hasta que la macro se expanda por primera vez. Esto le permite hacer que su expansión anterior sea parte de su propia definición. Sin embargo, dado que aparece durante su expansión, solo se puede usar una vez.
Aquí hay un código de muestra para verlo en acción
#define pushfoo _Pragma("push_macro(/"foo/")") //for convenience
#define popfoo _Pragma("pop_macro(/"foo/")")
#define foo 1
pushfoo //push the old value
#undef foo //so you don''t get a warning on the next line
#define foo popfoo foo , 2 //append to the previous value of foo
pushfoo
#undef foo
#define foo popfoo foo , 3
pushfoo
#undef foo
#define foo popfoo foo , 4
foo //this whole list will expand to something like popfoo foo popfoo foo popfoo foo , 4
//which will in turn expand to 1 , 2 , 3 , 4
foo //the second time this will expand to just 1
Esta opción debería hacer que la generación automática de código sea un poco más fácil, aunque desafortunadamente solo en gcc (quizás clang, no se haya probado)
Para ser sincero, no hay ninguna razón por la que pueda encontrar por qué esto debe funcionar; es muy probable que el comportamiento indefinido funcione. Supongo que la razón es que después de hacer estallar foo, la macro actual que se está expandiendo ya no está asociada con el nombre foo, que permite expandir el símbolo foo
, pero esa es solo mi conjetura