2010-07-22 36 views
34

Sé que estoy tratando de pegarme un tiro en la pierna;) Sin embargo, me permitirá hacer el resto (gran cantidad) de código más pequeño y más legible.¿Hay alguna manera de hacer un #define dentro de otro #define?

¿Hay alguna manera complicada de crear macro de preprocesador dentro de otra macro de preprocesador?

Aquí está el ejemplo, lo que estoy buscando. Mi escenario real es más complejo

// That's what I want to do and surely C++ doesn't like it. 
#define MACROCREATER(B) #define MACRO##B B+B 

void foo() 
{ 
MACROCREATOR(5) // This should create new macro (#define MACRO5 5+5) 

int a = MACRO5; // this will use new macro 
} 

Respuesta

13

No. Incluso si una macro se expande en algo que se parece a una directiva de preprocesamiento, la expansión no se evalúa como una directiva de preprocesamiento.

3

No. El preprocesador es de una sola pasada. No vuelve a evaluar las macroexpansiones.

¿Qué te compraría esto? Puede lograr lo mismo que su ejemplo simplemente "en línea" la segunda macro en la primera. por ejemplo:

#define MACRO(B) B+B 

void foo() 
{ 
    int a = MACRO(5); 
} 
39

El estándar de C++ dice (16.3.4.3):

El resultante completamente -macro reemplazado preprocesamiento contador secuencia [... de la expansión macro ...] no es procesada como una directiva de preprocesamiento incluso si similar a uno ...

Así que no, no hay manera 'oficial' de lograr lo que quiere con macros.

3

Como se indicó, uno puede #incluir un archivo en particular más de una vez con diferentes definiciones de macro activas. Esto puede hacer que sea práctico lograr algunos efectos que no podrían lograrse de manera práctica por otros medios.

Como un ejemplo simple, en muchos sistemas integrados la indirección del puntero es muy costosa en comparación con el acceso variable directo. El código que usa mucho direccionamiento indirecto del puntero puede ser dos veces más grande y lento que el código que simplemente usa variables. En consecuencia, si se usa una rutina particular con dos conjuntos de variables, en un escenario en el que normalmente se pasaría un puntero a una estructura y luego se usaría el operador de flecha, puede ser mucho más eficiente simplemente poner la rutina en su propio archivo (Normalmente uso la extensión .i) que es #incluida una vez sin macro _PASS2 definido, y una segunda vez con. Ese archivo puede entonces #ifdef _PASS2/# else para definir macros para todas las variables que deberían ser diferentes en las dos pasadas. A pesar de que el código se genera dos veces, en algunos micros que ocupará menos espacio que utilizando el operador de flecha con punteros pasados.

2

Eche un vistazo a m4. Es similar a cpp, pero recursivo y mucho más poderoso. He usado m4 para crear un lenguaje estructurado para ensambladores, p.

cmp r0, #0 
    if(eq) 
    mov r1, #0 
    else 
    add r1, #1 
    end 

El "si", "más" y "fin" son llamadas a macros m4 que escribí que generan saltos y etiquetas, el resto es el montaje nativo. Para anidar estas construcciones if/else/end, debe hacer define dentro de una macro.

6

Como complemento de las respuestas anteriores, si realmente quería comprobar la validez de proceso de un archivo de origen dos veces — que es casi definitivamente no lo que realmente quiere hacer — siempre se puede invocar el compilador de esta manera:

g++ -E input.cpp | g++ -c -x c++ - -o output.o 

es decir, ejecute el archivo a través del preprocesador, a continuación, ejecute la salida procesada previamente a través de la tubería a través de una rutina de recopilación completa, incluyendo un segundo paso de procesamiento previo. Para que esto tenga una posibilidad razonablemente buena de funcionar, me imagino que tendrías que ser bastante cuidadoso en la forma en que definiste y usaste tus macros, y en general es probable que no valga la pena y aumente la compilación. hora.

Si realmente quiere macros, use soluciones estándar basadas en macros. Si realmente quieres metaprogramación en tiempo de compilación, usa plantillas.

En una nota ligeramente relacionada, esto me recuerda que el lenguaje de trazado de rayos POV-Ray hizo un uso intensivo de un lenguaje de preprocesamiento bastante complejo, con directivas de control de flujo como #while que permitían la repetición condicional, cálculos en tiempo de compilación, y otras cosas así. Ojalá fuera así en C++, pero simplemente no lo es, así que lo hacemos de otra manera.