预处理器可变参数FOR_EACH宏与MSVC ++ 10兼容

时间:2013-02-06 15:36:04

标签: c++ visual-c++ foreach variadic-macros

我已经看到一些问题,要求对可变参数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是另一个宏。

1 个答案:

答案 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宏,我将不胜感激。