2009-12-10 7 views
9

Quello che mi piacerebbe fare (a fini di registrazione) è qualcosa di simile:CPP: evitare l'espansione delle macro di un parametro di funzione macro

Questo codice è stato scritto per mostrare il mio problema, codice vero e proprio è complessa e sì , ho buone ragioni per utilizzare le macro anche su C++ =)

# define LIB_SOME 1 
# define LIB_OTHER 2 

# define WHERE "at file #a, line #l, function #f: " 
// (look for syntax hightlighting error at SO xd) 
# define LOG_ERROR_SIMPLE(ptr, lib, str) ptr->log ("ERROR " str \ 
                " at library " #lib); 
# define LOG_ERROR(ptr, lib, str) LOG_ERROR_SIMPLE(ptr, lib, WHERE str) 

LOG_ERROR_SIMPLE (this, LIB_SOME, "doing something") 
LOG_ERROR (this, LIB_OTHER, "doing something else") 

LOG_ERROR_SIMPLE() scrive il in stringa del parametro lib (un nome di macro circondato da " ")

ma poi LOG_ERROR scrive il in stringa della macro già expande d ("2"). questo è previsto, dal momento che lib ha ottenuto la sua espansione prima di espandersi e chiamare LOG_ERROR_SIMPLE. ma questo non è ciò di cui ho bisogno.

Fondamentalmente la mia domanda è questa: come evitare macro l'espansione di un parametro funzione macro quando si chiama un'altra funzione macro?

C'è un trucco che uso che evita macro espansione:

LOG_ERROR(ptr, lib, str, x) LOG_ERROR_SIMPLE(ptr, x##lib, WHERE str) 

    LOG_ERROR(this, LIB_OTHER, "some error",) 

(incollare x e lib produce LIB_OTHER e questo valore viene utilizzato per chiamare LOG_ERROR_SIMPLE, la sua non macro espansa prima chiamata)

C'è un modo per ottenere questo stesso comportamento senza usare un trucco?

risposta

7

che sto facendo:

#include <cstdio> 

#define FOO 1 
#define BAR 2 

#define LOG_SIMPLE(ptr, lib, str) printf("%s\n", #lib); 
#define LOG(ptr, lib, str) LOG_SIMPLE(ptr, ##lib, str) 

int main() 
{ 
    LOG_SIMPLE(0, FOO, "some error"); 
    LOG(0, BAR, "some other error"); 
} 

che stampa:

FOO 
BAR 

Funziona con MSVC2005 ma non con gcc/g ++.


EDIT: per farlo funzionare con gcc/g ++ si può abusare macro variadic:

#include <stdio.h> 

#define FOO 1 
#define BAR 2 

#define LOG_SIMPLE(ptr, str, lib) printf("%s\n", #lib); 
#define LOG(ptr, str, lib, ...) LOG_SIMPLE(ptr, str, lib##__VA_ARGS__) 

int main() 
{ 
    LOG_SIMPLE(0, "some error", FOO); 
    LOG(0, "some other error", BAR); 
    LOG(0, "some other error", FOO, BAR); 
} 

Tuttavia, è la vostra disciplina di non usare la macro con troppi parametri. MSVC2005 stampa i

FOO 
BAR 
FOO2 

mentre le stampe gcc fuori

FOO 
BAR 
FOOBAR 
+0

Quando si utilizza il preprocessore di GCC (rimuovendo '# include' che non esiste), ottengo il programma corretto su stdout, ma un messaggio di errore su stderr. t.c: 11: 1: errore: incollare "," e "BAR" non fornisce un token di preelaborazione valido –

+0

qui, non funziona con gcc/g ++ –

+0

Bene, "non funziona" è un po 'forte. Ho ottenuto un programma compilabile su stdout quando ho eseguito 'gcc -E t.c'. –

0

Non credo che si può. Che cosa si potrebbe fare, però, è aggiungere uno strato di macro per farlo non staccarsi al suo posto:

#define WRAP(x) x 
#define LOG_ERROR(ptr, lib, str) LOG_ERROR_SIMPLE(ptr, lib, WHERE WRAP(str)) 
+1

BOOST_PP_IDENTITY (X) – KitsuneYMG

+0

@kts Ooh, whaddya sapere. Penso a qualcosa, e i bozzi di Boost sono waaaaaayay davanti a me. –

+0

non funziona WRAP o _IDENTITY .. perché (almeno in CPP) chiama LOG_ERROR_SIMPLE con WRAP () come parametro, e non come "che cosa è all'interno del nome ma non espanso" – conejoroy

0

È quasi avuto.Utilizzare

#define LOG_ERROR(ptr, lib, str) LOG_ERROR_SIMPLE(ptr, ##lib, WHERE str) 

Su gcc
LOG_ERROR(this, LIB_OTHER, "some error")
produce
this->log ("ERROR " "at file #a, line #l, function #f: " "some error" " at library " "LIB_OTHER");

Vorrei anche rimuovere il trailing ';' dal macro in modo che il codice sarà simile:
LOG_ERROR(this, LIB_OTHER, "some error");

+0

Penso che l'OP voglia evitare la citazione dell'argomento da cui deriva la domanda. Se "LIB_OTHER" andava bene con lui, penso che non avrebbe chiesto in primo luogo che –

+0

incollando lib con una virgola fornisse questo errore: incollando "," e "LIB_OTHER" non si fornisce un token di pre-elaborazione valido. c'è qualche carattere "neutro" o un parametro vuoto nascosto che potrei usare per incollare lib con "qualcosa di vuoto" e senza errori? – conejoroy

+0

Siamo spiacenti. Ho frainteso i tuoi bisogni. BOOST_PP_EMPTY è una macro che non si espande. Puoi anche provare/**/(questo è un commento in stile c vuoto nel caso in cui il markdown lo uccide) – KitsuneYMG

4

Se non è necessario l'alias lib espansi (cioe '1' & '2') nelle macro cpp, si potrebbe anche usare un enum invece di valori definiti.

+2

Anche se mi sarebbe piaciuto trovare la soluzione al mio problema di espansione macro, mi hai fatto ripensare a uno dei suoi elementi. Ho modificato le mie costanti macro in enumerazioni, il loro nome non ha espansioni macro (dato che non sono macro) e ora il problema non è risolto, ma è andato =) – conejoroy

+0

Ora voglio ancora risolverlo, ma per quanto riguarda il mio programma, grazie al tuo suggerimento non ho bisogno di .. – conejoroy