4

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

4

2 回答 2

8

现在已经准确掌握了 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__在可变参数宏的定义中传递给宏,则在替换为宏后对其进行求值,导致多个逗号分隔的参数被视为一个。为了解决这个问题,您必须延迟参数评估直到 after__VA_ARGS__被替换,通过将宏调用包装在 中EXPAND,强制宏调用被评估为字符串,替换__VA_ARGS__为这样做。只有在替换之后EXPAND才会调用宏,此时可变参数已经被替换。

FOR_EACH_NPS如果有人能提出一种紧凑地为更大的值生成宏的方法,我将不胜感激N

于 2013-02-06T17:25:20.040 回答
1

根据 Dylan 的回答,我编写了一个 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 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__)

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

于 2022-01-10T13:18:27.210 回答