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

Preprocessor variadic FOR_EACH macro compatible with MSVC++10(与 MSVC++10 兼容的预处理器可变参数 FOR_EACH 宏)

本文介绍了与 MSVC++10 兼容的预处理器可变参数 FOR_EACH 宏的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我看到了一些要求对可变参数 FOR_EACH 宏进行变体的问题.然而不幸的是,提供的答案与 VC++10 不兼容,因为它在传递给另一个宏时将 __VA_ARGS __ 扩展为一个参数.请有人提供仍然适用于 VC++10 的 C++11 兼容(因此向前兼容)版本.也许使用经常提到的解决方法",#define EXPAND(x) x,但是我不知道把它放在哪里以获得,例如,这个答案适用于 VC++10.

澄清一下,预期行为是 FOR_EACH(x, a, b, ...) 产生 x(a) x(b), ...,其中 x 是另一个宏.

解决方案

现在已经准确掌握了 VC++10 编译器错误的工作原理,我能够根据

的后半部分自己提出这样的宏a href="https://stackoverflow.com/a/1872506/864340">这个答案.

#define EXPAND(x) x#define FOR_EACH_1(what, x, ...) what(x)#define FOR_EACH_2(what, x, ...)什么(x);扩展(FOR_EACH_1(什么,__VA_ARGS__))#define FOR_EACH_3(what, x, ...)什么(x);扩展(FOR_EACH_2(什么,__VA_ARGS__))#define FOR_EACH_4(what, x, ...)什么(x);扩展(FOR_EACH_3(什么,__VA_ARGS__))#define FOR_EACH_5(what, x, ...)什么(x);扩展(FOR_EACH_4(什么,__VA_ARGS__))#define FOR_EACH_6(what, x, ...)什么(x);扩展(FOR_EACH_5(什么,__VA_ARGS__))#define FOR_EACH_7(what, x, ...)什么(x);扩展(FOR_EACH_6(什么,__VA_ARGS__))#define FOR_EACH_8(what, x, ...)什么(x);扩展(FOR_EACH_7(什么,__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 连接(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 中的 bug 是,如果 __VA_ARGS__ 被传递给可变参数宏定义内的宏,它会在替换到宏后被评估,导致多个逗号分隔的参数被视为一.要解决这个问题,您必须延迟参数评估,直到替换 __VA_ARGS__ 之后,将宏调用包装在 EXPAND 中,强制将宏调用评估为字符串,替换 __VA_ARGS__代码>__VA_ARGS__ 这样做.只有在替换到 EXPAND 之后才调用宏,此时可变参数已经被替换.

附言如果有人可以建议一种紧凑地生成 FOR_EACH_N 宏的方法,以获取更大的 N 值,我将不胜感激.

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.

解决方案

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.

这篇关于与 MSVC++10 兼容的预处理器可变参数 FOR_EACH 宏的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!

本文标题为:与 MSVC++10 兼容的预处理器可变参数 FOR_EACH 宏

基础教程推荐