我想使用C++预处理器为几个不同的值生成几段代码。我在表生成宏中输入了所有这些值。然而,代码的某些部分只需要为值的某些(析取(子集生成。因此,我希望有小的表生成宏,然后将它们合并到一个大的宏中(用于必须为所有宏生成的代码(。到目前为止,这部分工作完美无瑕。
然而,我需要使用逗号作为代码某些部分的分隔符(确切地说是为了生成枚举(。不幸的是,这个逗号被替换得太早了(即在宏的函数调用被替换之前(。这里有一个例子可以说明我的问题:
#include <iostream>
#define A(F, SEP) F(one) SEP F(two)
#define B(F, SEP) F(three) SEP F(four)
#define C(F, SEP) A(F, SEP) SEP B(F, SEP)
#define SOME_F(x) x
#define SOME_SEP ,
enum {C(SOME_F, SOME_SEP)} ENUM;
int main()
{
#define ANOTHER_F(x) std::cout << #x << std::endl;
#define ANOTHER_SEP
A(ANOTHER_F, ANOTHER_SEP)
return 0;
}
在这里,我想生成一个包含所有值的枚举(它在示例中未使用,但在我的实际代码中我需要它(,并打印子集A的所有值。如果我试图编译此示例,它将失败,并返回错误error: macro "A" passed 3 arguments, but takes just 2
(B的消息相同(。这似乎是因为SOME_SEP
宏在A
被替换之前被替换(并且尝试使用A(F, ,)
(。
对此,一个相当简单(但很难看(的修复方法是将SEP参数替换为类似函数的宏,而不是类似对象的宏(不过,每个调用都必须添加括号(。然而,我想使用类似对象的宏来解决这个问题。在我的网络搜索过程中,我发现很多人都有类似的问题,但他们想传递一个模板类型(因此可以通过使用大括号来解决这个问题(这不适用于逗号作为分隔符((。
只需使用括号,然后将其移除。
#include <iostream>
#define EXP(...) __VA_ARGS__
#define A(F, SEP) F(one) EXP SEP F(two)
#define B(F, SEP) F(three) EXP SEP F(four)
#define C(F, SEP) A(F, SEP) EXP SEP B(F, SEP)
#define SOME_F(x) x
enum {C(SOME_F, (,))} ENUM;
int main() {
#define ANOTHER_F(x) std::cout << #x << std::endl;
A(ANOTHER_F, ())
}
总的来说,这是一个奇怪的用法,看起来很奇怪。考虑使用BOOST_PP_SEQ_FOR_EACH
和类似的FOREACH_*
宏。在宏中定义要迭代的元素列表是很奇怪的——我希望它在外部定义并作为参数传递。类似:
#define LIST1 (one)(two)
#define CALLBACK(x) x
SUPER_FOREACH(LIST1, CALLBACK, (,))
另请参阅如何将枚举类型变量转换为字符串?如果你想字符串化一个枚举。