【问题标题】:Preprocessor variadic FOR_EACH macro compatible with MSVC++10与 MSVC++10 兼容的预处理器变量 FOR_EACH 宏
【发布时间】:2013-02-06 15:36:03
【问题描述】:

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

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

【问题讨论】:

  • 答案在哪里提供?请链接到您提到的问题。
  • 会的,我很难再次找到它们。同时,请参阅问题第一段末尾的链接答案。

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


【解决方案1】:

现在已经准确掌握了 VC++10 编译器 bug 的工作原理,我自己根据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 个参数,以及 @987654326使用@宏解决方法。

VC++10 中的错误是,如果将__VA_ARGS__ 传递给可变参数宏定义中的宏,则在替换为宏后对其进行求值,从而导致多个逗号分隔的参数被视为一个。为了解决这个问题,您必须延迟参数评估直到 __VA_ARGS__ 被替换后,通过将宏调用包装在 EXPAND 中,强制宏调用被评估为字符串,替换 __VA_ARGS__ 这样做。只有在替换为EXPAND 之后才会调用宏,此时可变参数已被替换。

附:如果有人能建议一种方法来紧凑地生成 FOR_EACH_N 宏以获得更大的 N 值,我将不胜感激。

【讨论】:

  • 有兼容 C99 的版本吗?我收到warning: ISO C99 requires rest arguments to be used 之类的错误
【解决方案2】:

根据Dylan的回答,我写了一段python代码生成for_each宏N次。

下面是代码:

from builtins import *

# number of generated for_each cases.
iter_max = 19

# override this with your own!
prefix = "MY_"  # define your own macro prefix, which ends with under_score if not empty.
internal_prefix = "internal_"

# CODE ------------------------------------------------------------------------------------------------------
INTERNAL_ = f"{internal_prefix}{prefix}"

fmt_numstr = "{}"  # f"{{:0>{max_digit}}}"

EXPAND = f"{INTERNAL_}EXPAND"

FOR_EACH = f"{INTERNAL_}FOR_EACH_"
FOR_EACH_N = f"{FOR_EACH}{fmt_numstr}"

OUT = "#pragma once\n"

OUT += f"#define {EXPAND}(x) x\n"
OUT += f"#define {FOR_EACH_N.format(1)}(what, x, ...) what(x)\n"

for i in range(2, iter_max + 1):
    OUT += f"#define {FOR_EACH_N.format(i)}(what, x, ...) " \
           f"what(x);" \
           f"{EXPAND}({FOR_EACH_N.format(i - 1)}(what, __VA_ARGS__))\n"

FOR_EACH_NARG = f"{INTERNAL_}FOR_EACH_NARG"
FOR_EACH_RSEQ_N = f"{INTERNAL_}FOR_EACH_RSEQ_N"
FOR_EACH_ARG_N = f"{INTERNAL_}FOR_EACH_ARG_N"

OUT += f"#define {FOR_EACH_NARG}(...) {FOR_EACH_NARG}_(__VA_ARGS__, {FOR_EACH_RSEQ_N}())\n"
OUT += f"#define {FOR_EACH_NARG}_(...) {EXPAND}({FOR_EACH_ARG_N}(__VA_ARGS__))\n"

underscore_sequence = ""
inverse_sequence = ""
for i in range(1, iter_max + 1):
    underscore_sequence += f"_{i}{',' if i < iter_max else ''}"

for i in range(0, iter_max + 1):
    inverse_sequence += f"{fmt_numstr}{',' if i < iter_max else ''} ".format(iter_max - i)

OUT += f"#define {FOR_EACH_ARG_N}({underscore_sequence}, N, ...) N\n"
OUT += f"#define {FOR_EACH_RSEQ_N}() {inverse_sequence}\n"

CONCATENATE = f"{INTERNAL_}CONCATENATE"

OUT += f"#define {CONCATENATE}(x,y) x##y\n"

INTERNAL_FOR_EACH = f"{INTERNAL_}FOR_EACH_"

OUT += f"#define {INTERNAL_FOR_EACH}(N, what, ...) {EXPAND}({CONCATENATE}({FOR_EACH}, N)(what, __VA_ARGS__))\n"
OUT += f"#define {prefix}FOR_EACH(what, ...) {INTERNAL_FOR_EACH}({FOR_EACH_NARG}(__VA_ARGS__), what, __VA_ARGS__)\n"

print(OUT)

执行结果为:

#pragma once
#define internal_MY_EXPAND(x) x
#define internal_MY_FOR_EACH_1(what, x, ...) what(x)
#define internal_MY_FOR_EACH_2(what, x, ...) what(x);internal_MY_EXPAND(internal_MY_FOR_EACH_1(what, __VA_ARGS__))
#define internal_MY_FOR_EACH_3(what, x, ...) what(x);internal_MY_EXPAND(internal_MY_FOR_EACH_2(what, __VA_ARGS__))
#define internal_MY_FOR_EACH_4(what, x, ...) what(x);internal_MY_EXPAND(internal_MY_FOR_EACH_3(what, __VA_ARGS__))
#define internal_MY_FOR_EACH_5(what, x, ...) what(x);internal_MY_EXPAND(internal_MY_FOR_EACH_4(what, __VA_ARGS__))
#define internal_MY_FOR_EACH_6(what, x, ...) what(x);internal_MY_EXPAND(internal_MY_FOR_EACH_5(what, __VA_ARGS__))
#define internal_MY_FOR_EACH_7(what, x, ...) what(x);internal_MY_EXPAND(internal_MY_FOR_EACH_6(what, __VA_ARGS__))
#define internal_MY_FOR_EACH_8(what, x, ...) what(x);internal_MY_EXPAND(internal_MY_FOR_EACH_7(what, __VA_ARGS__))
#define internal_MY_FOR_EACH_9(what, x, ...) what(x);internal_MY_EXPAND(internal_MY_FOR_EACH_8(what, __VA_ARGS__))
#define internal_MY_FOR_EACH_10(what, x, ...) what(x);internal_MY_EXPAND(internal_MY_FOR_EACH_9(what, __VA_ARGS__))
#define internal_MY_FOR_EACH_11(what, x, ...) what(x);internal_MY_EXPAND(internal_MY_FOR_EACH_10(what, __VA_ARGS__))
#define internal_MY_FOR_EACH_12(what, x, ...) what(x);internal_MY_EXPAND(internal_MY_FOR_EACH_11(what, __VA_ARGS__))
#define internal_MY_FOR_EACH_13(what, x, ...) what(x);internal_MY_EXPAND(internal_MY_FOR_EACH_12(what, __VA_ARGS__))
#define internal_MY_FOR_EACH_14(what, x, ...) what(x);internal_MY_EXPAND(internal_MY_FOR_EACH_13(what, __VA_ARGS__))
#define internal_MY_FOR_EACH_15(what, x, ...) what(x);internal_MY_EXPAND(internal_MY_FOR_EACH_14(what, __VA_ARGS__))
#define internal_MY_FOR_EACH_16(what, x, ...) what(x);internal_MY_EXPAND(internal_MY_FOR_EACH_15(what, __VA_ARGS__))
#define internal_MY_FOR_EACH_17(what, x, ...) what(x);internal_MY_EXPAND(internal_MY_FOR_EACH_16(what, __VA_ARGS__))
#define internal_MY_FOR_EACH_18(what, x, ...) what(x);internal_MY_EXPAND(internal_MY_FOR_EACH_17(what, __VA_ARGS__))
#define internal_MY_FOR_EACH_19(what, x, ...) what(x);internal_MY_EXPAND(internal_MY_FOR_EACH_18(what, __VA_ARGS__))
#define internal_MY_FOR_EACH_NARG(...) internal_MY_FOR_EACH_NARG_(__VA_ARGS__, internal_MY_FOR_EACH_RSEQ_N())
#define internal_MY_FOR_EACH_NARG_(...) internal_MY_EXPAND(internal_MY_FOR_EACH_ARG_N(__VA_ARGS__))
#define internal_MY_FOR_EACH_ARG_N(_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13,_14,_15,_16,_17,_18,_19, N, ...) N
#define internal_MY_FOR_EACH_RSEQ_N() 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 
#define internal_MY_CONCATENATE(x,y) x##y
#define internal_MY_FOR_EACH_(N, what, ...) internal_MY_EXPAND(internal_MY_CONCATENATE(internal_MY_FOR_EACH_, N)(what, __VA_ARGS__))
#define MY_FOR_EACH(what, ...) internal_MY_FOR_EACH_(internal_MY_FOR_EACH_NARG(__VA_ARGS__), what, __VA_ARGS__)

您可以自定义宏前缀和内部前缀以供自己使用。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-04-17
    • 1970-01-01
    • 2010-11-23
    • 2015-02-26
    • 1970-01-01
    • 2015-04-15
    相关资源
    最近更新 更多