2013-10-18 2 views
8

Sto usando i macro da questo post attraverso i miei argomenti. Tutto funziona alla grande! Tuttavia, c'è un modo per combinare questi due CCB_CREATE e CCB_CREATE_MORE?C++ Macro loop preprocessore __VA_ARGS__ 1 vs 2+ argomenti

Ho bisogno di estrarre il primo argomento object_type per scrivere codice aggiuntivo. Gli ulteriori object_type utilizzeranno il ciclo FOR_EACH da inserire nella mappa.

Il compilatore si lamenta quando ho solo un argomento quando si utilizza CCB_CREATE_MORE(Type1). Per risolvere il problema ho creato un'altra macro per gestire tale CCB_CREATE(Type1). Sperando di trovare una soluzione intelligente per combinare questi due in una macro elegante. Qualche idea?

#define INSERT_LOADER_MAP(object_type) loader_map.insert(make_pair(#object_type, object_type##Loader::loader())) 


#define CCB_CREATE_MORE(object_type,...) \ 
static CCNode * create##object_type##Node() { \ 
    std::map<std::string, CCNodeLoader*> loader_map; \ 
    std::string classname = #object_type; \ 
    FOR_EACH(INSERT_LOADER_MAP,object_type,__VA_ARGS__); \ 
    return loadCCBFile((classname + ".ccbi").c_str(), loader_map); \ 
} 


#define CCB_CREATE(object_type) \ 
static CCNode * create##object_type##Node() { \ 
    std::map<std::string, CCNodeLoader*> loader_map; \ 
    std::string classname = #object_type; \ 
    INSERT_LOADER_MAP(object_type); \ 
    return loadCCBFile((classname + ".ccbi").c_str(), loader_map); \ 
} 
+5

Non è consigliabile utilizzare '__type__'. È un identificatore riservato. – chris

+0

Grazie per averlo indicato. Ho appena fatto una ricerca e ci ho sostituito. – docchang

risposta

5

Il compilatore è probabile lamenta la virgola finale quando la lista argomenti variadic è vuoto. GCC e Studio compilatori visivi supportano l'estensione non standard ##__VA_ARGS__ per sopprimere la virgola finale:

#define FOO(fmt, ...) printf(fmt, ##__VA_ARGS__) 

The Studio compilatori visivi potranno anche sopprimere la virgola a anche senza l'estensione ##.

Vedere documentazione GCC here e documentazione di Visual Studio here.

Se è necessaria una soluzione conforme agli standard, ne è disponibile una in risposta a this question.

Quindi, se si utilizza uno gcc o Visual Studio, si dovrebbe essere in grado di utilizzare la macro originale con questa semplice modifica:

#define CCB_CREATE(object_type,...) \ 
static CCNode * create##object_type##Node() { \ 
    std::map<std::string, CCNodeLoader*> loader_map; \ 
    std::string classname = #object_type; \ 
    FOR_EACH(INSERT_LOADER_MAP,object_type,##__VA_ARGS__); \ 
    return loadCCBFile((classname + ".ccbi").c_str(), loader_map); \ 
} 

Edit: Lei avrebbe bisogno di utilizzare il ##__VA_ARGS__ estensione la macro FOR_EACH(), o la modifica più elegante suggerita da ugoren.

2

Oltre a Chris Olsen's suggestion, è necessaria una leggera modifica al FOR_EACH macro:

#define FOR_EACH(what, ...) FOR_EACH_(FOR_EACH_NARG(__VA_ARGS__), what, __VA_ARGS__) 

Come risultato, FOR_EACH(X, a) diventerà X(a) (anziché X(a); X();). Ciò elimina una chiamata vuota INSERT_LOADER_MAP.