2013-10-18 42 views
8

我使用這個post的宏循環遍歷我的參數。一切都很好!但是,有沒有辦法將這兩個CCB_CREATECCB_CREATE_MORE結合起來?C++預處理器宏循環__VA_ARGS__ 1 vs 2+參數

我需要提取第一個參數object_type來編寫其他代碼。額外的object_type將使用FOR_EACH循環來插入地圖。

編譯器投訴,當我只有一個參數時使用CCB_CREATE_MORE(Type1)。爲了解決這個問題,我做了另一個宏來處理那個CCB_CREATE(Type1)。希望找到一個巧妙的解決方案,將這兩個結合成一個優雅的宏。有任何想法嗎?

#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

我不推薦使用'__type__'。這是一個保留的標識符。 – chris

+0

謝謝你指出。只是做了一個搜索和替換。 – docchang

回答

5

當可變參數列表爲空時,編譯器可能會抱怨尾隨逗號。 GCC和Visual Studio編譯器支持非標準擴展##__VA_ARGS__壓制後面的逗號:

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

在Visual Studio編譯器也將壓制後面的逗號,即使沒有##擴展。

請參閱GCC文檔here和Visual Studio文檔here

如果您需要符合標準的解決方案,請在this question的答案中詳細說明。

因此,如果您使用的是GCC或Visual Studio,你應該能夠使用你原來的宏與這個簡單的變化:

#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); \ 
} 

編輯: 你會需要使用##__VA_ARGS__擴展中還有FOR_EACH()宏,或者ugoren建議的更優雅的修改。

2

除了Chris Olsen's suggestion,需要向FOR_EACH宏略有變化:

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

結果,FOR_EACH(X, a)將成爲X(a)(代替X(a); X();)。這消除了一個空的INSERT_LOADER_MAP調用。