C’è un modo per fare un #define all’interno di un altro #define?

So che sto cercando di spararmi a una gamba;) Tuttavia, mi consentirà di rendere il resto (grande quantità) di codice più piccolo e più leggibile.

C’è qualche modo complicato per creare macro preprocessore all’interno di un’altra macro di preprocessore?

Ecco l’esempio, quello che sto cercando. Il mio scenario reale è più complesso

// 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 } 

Lo standard C ++ dice (16.3.4.3):

La risultante sequenza di token di preprocessing completamente sostituita da macro [… dell’espansione macro …] non viene elaborata come una direttiva di pre-elaborazione anche se somiglia a una …

Quindi no, non esiste un modo “ufficiale” per ottenere ciò che vuoi con i macro.

No. Anche se una macro si espande in qualcosa che assomiglia a una direttiva di pre-elaborazione, l’espansione non viene valutata come una direttiva di pre-elaborazione.

Come supplemento alle risposte di cui sopra, se volessi davvero pre-processare un file sorgente due volte – che non è quasi sicuramente quello che vuoi veramente fare – potresti sempre invocare il tuo compilatore in questo modo:

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

Ovvero, eseguire il file attraverso il preprocessore, quindi eseguire l’output preelaborato tramite pipe attraverso una routine di compilazione completa, incluso un secondo passaggio di pre-elaborazione. Affinché ciò abbia una ragionevole possibilità di funzionare, immagino che dovresti essere piuttosto attento nel modo in cui hai definito e usato i tuoi macro, e tutto sumto probabilmente non varrebbe la pena e l’aumento di build tempo.

Se vuoi davvero macro, usa soluzioni standard basate su macro. Se si desidera realmente eseguire la metaprogrammazione in fase di compilazione, utilizzare i modelli.

Su una nota leggermente correlata, questo mi ricorda il fatto che il linguaggio di raytracing POV-Ray ha fatto un uso pesante di un linguaggio di preprocessing piuttosto complesso, con direttive di controllo del stream come #while che consentiva la ripetizione condizionale, calcoli in fase di compilazione e altri Gli extra. Sarebbe stato così in C ++, ma semplicemente non lo è, quindi lo facciamo semplicemente in un altro modo.

No. Il pre-processore è single-pass. Non rivaluta le espansioni di macro.

Cosa ti avrebbe comprato, comunque? Puoi realizzare la stessa cosa del tuo esempio semplicemente “inserendo” la seconda macro nella prima. per esempio:

 #define MACRO(B) B+B void foo() { int a = MACRO(5); } 

Come notato, è ansible # includere un file particolare più di una volta con diverse definizioni di macro attive. Ciò può rendere pratico ottenere alcuni effetti che non potrebbero essere praticamente raggiunti con altri mezzi.

Come semplice esempio, su molti sistemi embedded il puntatore indiretto è molto costoso rispetto all’accesso diretto diretto. Il codice che usa molto puntatore indiretto può benissimo essere due volte più grande e lento del codice che usa semplicemente delle variabili. Di conseguenza, se una particolare routine viene utilizzata con due insiemi di variabili, in uno scenario in cui si passerebbe di solito in un puntatore a una struttura e quindi si utilizza l’operatore della freccia, potrebbe essere molto più efficiente mettere semplicemente la routine in un proprio file (Solitamente uso l’estensione .i) che è #inclusa una volta senza macro _PASS2 definita, e una seconda volta con. Quel file può quindi #ifdef _PASS2 / # else per definire macro per tutte le variabili che dovrebbero essere diverse sui due passaggi. Anche se il codice viene generato due volte, su alcuni micros che richiedono meno spazio rispetto all’utilizzo dell’operatore di freccia con i puntatori passati.

Dai un’occhiata a m4. È simile a cpp, ma ricorsivo e molto più potente. Ho usato m4 per creare un linguaggio strutturato per gli assemblatori, ad es

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

“If”, “else” e “end” sono chiamate ai macro m4 che ho scritto che generano salti ed etichette, il resto è assemblaggio nativo. Per annidare questi costrutti if / else / end, è necessario definire le definizioni all’interno di una macro.