我已经看到一些问题,要求对可变参数FOR_EACH
宏进行变换。但遗憾的是,提供的答案与VC ++ 10不兼容,因为它在传递给另一个宏时将__VA_ARGS __扩展为一个参数。请有人可以提供符合C ++ 11(因此向前兼容)的版本,仍然适用于VC ++ 10。也许使用经常提到的“变通方法”#define EXPAND(x) x
,但是我不知道在哪里放置它,例如,this answer的后一个广义部分在VC +中工作10。
为了澄清,预期的行为是FOR_EACH(x, a, b, ...)
生成x(a) x(b), ...
,其中x是另一个宏。
答案 0 :(得分:6)
现在已经掌握了VC ++ 10编译器错误的工作原理,我自己能够根据this answer的后半部分提出这样一个宏。
#define EXPAND(x) x
#define FOR_EACH_1(what, x, ...) what(x)
#define FOR_EACH_2(what, x, ...)\
what(x);\
EXPAND(FOR_EACH_1(what, __VA_ARGS__))
#define FOR_EACH_3(what, x, ...)\
what(x);\
EXPAND(FOR_EACH_2(what, __VA_ARGS__))
#define FOR_EACH_4(what, x, ...)\
what(x);\
EXPAND(FOR_EACH_3(what, __VA_ARGS__))
#define FOR_EACH_5(what, x, ...)\
what(x);\
EXPAND(FOR_EACH_4(what, __VA_ARGS__))
#define FOR_EACH_6(what, x, ...)\
what(x);\
EXPAND(FOR_EACH_5(what, __VA_ARGS__))
#define FOR_EACH_7(what, x, ...)\
what(x);\
EXPAND(FOR_EACH_6(what, __VA_ARGS__))
#define FOR_EACH_8(what, x, ...)\
what(x);\
EXPAND(FOR_EACH_7(what, __VA_ARGS__))
#define FOR_EACH_NARG(...) FOR_EACH_NARG_(__VA_ARGS__, FOR_EACH_RSEQ_N())
#define FOR_EACH_NARG_(...) EXPAND(FOR_EACH_ARG_N(__VA_ARGS__))
#define FOR_EACH_ARG_N(_1, _2, _3, _4, _5, _6, _7, _8, N, ...) N
#define FOR_EACH_RSEQ_N() 8, 7, 6, 5, 4, 3, 2, 1, 0
#define CONCATENATE(x,y) x##y
#define FOR_EACH_(N, what, ...) EXPAND(CONCATENATE(FOR_EACH_, N)(what, __VA_ARGS__))
#define FOR_EACH(what, ...) FOR_EACH_(FOR_EACH_NARG(__VA_ARGS__), what, __VA_ARGS__)
使用示例:
#define callMember(o, f) o.f();
#define callMember_o(f) callMember(o, f)
FOR_EACH(callMember_o, doSomething, doSomethingElse);
与
相同o.doSomething(); o.doSomethingElse();
此解决方案与链接答案中的解决方案类似,不同之处在于FOR_EACH(what, x, ...)
中使用一个元素调用时的零长度可变参数列表导致伪逗号使FOR_EACH_NARG计数2个参数而不是1个参数,并且使用EXPAND
宏解决方法。
VC ++ 10中的错误是如果将__VA_ARGS__
传递给可变参数宏定义中的宏,则在替换为宏之后对其进行求值,从而将多个逗号分隔的参数视为一个。要解决这个问题,你必须延迟参数评估,直到替换__VA_ARGS__
为止,方法是将宏调用包装在EXPAND
中,强制将宏调用计算为字符串,用__VA_ARGS__
代替所以。只有在被调用的宏被替换为EXPAND
之后,可变参数才被替换。
P.S。如果有人能提出一种方法来为FOR_EACH_N
更大的值紧凑地生成N
宏,我将不胜感激。