Preprocessor variadic FOR_EACH macro compatible with MSVC++10

风格不统一 提交于 2019-11-28 05:28:52

问题


I've seen a few questions asking for a variation on a variadic FOR_EACH macro. However unfortunately the answers provided are incompatible with VC++10 due to it expanding __VA_ARGS __ as one argument when passed to another macro. Please could someone provide a C++11 compliant (thus forward-compatible) version that still works with VC++10. Perhaps using the "workaround" that is often mentioned, #define EXPAND(x) x, however I don't know where to put this in order to get, for example, the latter generalised part of this answer to work in VC++10.

To clarify, the intended behaviour is for FOR_EACH(x, a, b, ...) to produce x(a) x(b), ..., where x is another macro.


回答1:


Having now grasped exactly how the VC++10 compiler bug works, I was able to come up with such a macro myself, based on the latter part of 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__)

Example usage:

#define callMember(o, f) o.f();
#define callMember_o(f) callMember(o, f)
FOR_EACH(callMember_o, doSomething, doSomethingElse);

is the same as

o.doSomething(); o.doSomethingElse();

This solution is similar to that in the linked answer, except that the zero length variadic argument list in FOR_EACH(what, x, ...) when called with one element caused a spurious comma that makes FOR_EACH_NARG count 2 arguments instead of 1 argument, and the EXPAND macro workaround is used.

The bug in VC++10 is that if __VA_ARGS__ is passed to a macro within the definition of a variadic macro, it is evaluated after substitution into the macro, causing multiple comma separated arguments to be treated as one. To get around this you must delay argument evaluation until after __VA_ARGS__ is substituted, by wrapping the macro call in EXPAND, forcing the macro call to be evaluated as a string, substituting __VA_ARGS__ to do so. Only after the substitution into EXPAND is the macro called, by which point the variadic arguments are already substituted.

P.S. I would be grateful if anyone can suggest a method for compactly producing FOR_EACH_N macros for much larger values of N.



来源:https://stackoverflow.com/questions/14732803/preprocessor-variadic-for-each-macro-compatible-with-msvc10

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!