预处理器可变参数FOR_EACH宏与 MSVC++10 兼容
Preprocessor variadic FOR_EACH macro compatible with MSVC++10
我看到过一些问题,要求变体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__)
您可以自定义宏前缀和内部前缀供您自己使用。
- VS2017 #error: : snprintf 的宏定义与标准库函数声明冲突
- 将宏与C++和UnitTest++一起使用
- foreach宏的格式与clang格式的循环相同
- 模板与宏C++错误代码样板
- #ifdef 宏与 -Wpedantic 和 "extra" 分号
- 如何在 C 宏中将变量字符串与文字字符串连接起来?
- C 参考与宏替换一样工作
- 如何在 C++ 与 CPLEX 中实现宏节点回调
- 使用##预处理器操作员与另一个宏输出
- 如何将 #ifndef 与宏参数一起使用
- 在VS2013与VS2017的printf函数中使用宏
- C :与宏定义的字符串Concat Constant String
- C++中的"container_of"宏,具有与 C 相同的签名
- 如何处理windows.h中的max宏与std中的max冲突
- 宏与如果里面
- 调试宏与调试变量
- C++:有没有一种方法可以让这个反射宏与IntelliSense一起工作
- 将MFC宏与模板一起使用
- 预处理器可变参数FOR_EACH宏与 MSVC++10 兼容
- 我可以将 _T() 宏与变量一起使用吗?