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

C++ Preprocessor macro loop __VA_ARGS__ 1 vs 2+ arguments

本文关键字:参数 ARGS VA 处理器 循环 C++ 预处理      更新时间:2023-10-16

我正在使用这篇文章中的宏来循环我的论点。一切都很好!但是,有没有办法将这两种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); 
}

当可变参数列表为空时,编译器可能会抱怨尾随逗号。 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); 
}

编辑:您还需要在FOR_EACH()宏中使用##__VA_ARGS__扩展,或者使用ugoren建议的更优雅的修改。

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

除了 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调用。