8

我正在使用这篇文章中的宏循环我的参数。一切都很好!但是,有没有办法将这两者结合CCB_CREATE起来CCB_CREATE_MORE

我需要提取第一个参数object_type来编写额外的代码。额外object_type的 s 将使用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); \
}
4

2 回答 2

6

当可变参数列表为空时,编译器可能会抱怨尾随逗号。GCC 和 Visual Studio 编译器支持非标准扩展##__VA_ARGS__来抑制尾随逗号:

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

##即使没有扩展名,Visual Studio 编译器也会抑制尾随逗号。

请参阅此处的GCC 文档和此处的 Visual Studio 文档。

如果您需要符合标准的解决方案,请参阅此问题的答案中的详细说明。

因此,如果您使用 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__)
于 2013-10-20T07:26:39.047 回答
2

除了Chris Olsen 的建议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

于 2013-10-20T08:22:33.723 回答