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

Preprocessor variadic FOR_EACH macro compatible with MSVC++10

本文关键字:EACH 宏与 MSVC++10 兼容 FOR 处理器 变参 参数 预处理      更新时间:2023-10-16

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

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

现在已经完全掌握了 VC++10 编译器错误的工作原理,我能够根据这个答案的后半部分自己想出这样一个宏。

#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 之后,才会调用宏,此时可变参数已被替换。

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

我根据迪伦的回答编写了一个 python 代码来生成 N 次for_each宏。

下面是代码:

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 oncen"
OUT += f"#define {EXPAND}(x) xn"
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, ...) Nn"
OUT += f"#define {FOR_EACH_RSEQ_N}() {inverse_sequence}n"
CONCATENATE = f"{INTERNAL_}CONCATENATE"
OUT += f"#define {CONCATENATE}(x,y) x##yn"
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__)

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