C ++预处理器宏循环__VA_ARGS__ 1 vs 2+参数

时间:2013-10-18 02:48:29

标签: c++ macros

我正在使用此post循环遍历我的参数的宏。一切都很棒!但是,有没有办法将这两个CCB_CREATECCB_CREATE_MORE结合起来?

我需要提取第一个参数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); \
}

2 个答案:

答案 0 :(得分: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建议的更优雅的修改。

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

答案 1 :(得分: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调用。