免责声明 1:
老实说,我不建议你在宏后面做这样的机器。它们将成为巨大的维护负担,回报微乎其微。如果您可以使用其他更易于维护的抽象来做到这一点,那么从长远来看对您会更好。
免责声明 2:
我现在正在写这个没有编译器。我可能有语法错误,但这些是构建此解决方案的通用构建块。
免责声明说,这是可以做到的——但不是很好。
这里有几个问题需要用大量的宏技巧来解决:
- 您希望扩展包含
__VA_ARGS__ / 2 的大小(在扩展时)
- 您希望
__VA_ARGS__ 的扩展产生Variant(<arg 1>), Variant(<arg 3>), Variant(<arg 5>), Variant()
- 您希望
__VA_ARGS__ 的扩展产生Variant[size]{args[0], args[1], args[2], ...}
首先,我将创建一个名为 JOIN 的助手:
#define JOIN(a, b) JOIN_H(a, b)
#define JOIN_H(a, b) a ## b
这可能看起来很傻,但实际上它的作用是确保被连接在一起的宏在被连接之前会被求值 -- 这样被调用的宏函数就会正确地用它们的 实例化一个连接。 em>result 而不是全名。
获取__VA_ARGS__ / 2的大小
获取__VA_ARGS__ 的大小通常需要两个宏:
- 将
__VA_ARGS__, N, N-1, N-2, ... 传递到辅助宏中,并且
- 另一个在末尾提取
N。
类似:
#define COUNT_VA_ARGS(...) \
COUNT_VA_ARGS_H(__VA_ARGS__, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)
#define COUNT_VA_ARGS_H(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, N,...) N
这是有效的,因为第一个传递了__VA_ARGS__ 的所有参数并从第 N 个数字倒数,然后我们提取N。
在您的情况下,您需要__VA_ARGS__ / 2,因此您需要将这些参数加倍
#define COUNT_VA_ARGS(...) \
COUNT_VA_ARGS_H(__VA_ARGS__, 10, 10, 9, 9, 8, 8, 7, 7, 6, 6, 5, 5, 4, 4, 3, 3, 2, 2, 1, 1, 0, 0)
#define COUNT_VA_ARGS_H(_1, _1, _2, _2, _3, _3, _4, _4, _5, _5, _6, _6, _7, _7, _8, _8, _9, _9, _10, _10, N,...) N
使__VA_ARGS__ 产生Wrap(<arg 1>), Wrap(<arg 3>), ...
与 C++ 可变参数模板不同,宏不能具有可以包装每个参数的扩展表达式。要在宏中模拟这一点,您几乎必须明确定义 N 个扩展,然后调用它,您需要组合一个宏的结果来调用它。
#define WRAP_VA_ARGS_0(wrap)
#define WRAP_VA_ARGS_1(wrap,x0) wrap(x0)
...
#define WRAP_VA_ARGS_10(wrap,x0,x1, ..., x10) wrap(x0), wrap(x1), ..., wrap(x10)
// Call into one of the concrete ones above
#define WRAP_VA_ARGS(wrap, __VA_ARGS__) JOIN(WRAP_VA_ARGS_, COUNT_VA_ARGS(__VA_ARGS__))(__VA_ARGS__)
由于表达式实际上需要其中的每个 other 参数,因此您将再次需要将参数加倍:
#define WRAP_VA_ARGS_0(wrap)
#define WRAP_VA_ARGS_1(wrap,x0type,x0) wrap(x0)
#define WRAP_VA_ARGS_2(wrap,x0type,x0,x1type,x1) wrap(x0), wrap(x1)
...
现在调用 WRAP_VA_ARGS(Variant, int, A, float, B) 将创建 Variant(A), Variant(B)
创建索引值列表
与上面的包装类似,您需要找到一种方法来生成数字列表并将其包装。同样,这必须委托给计数包装器
#define WRAP_COUNT_VA_ARGS_0(wrap)
#define WRAP_COUNT_VA_ARGS_1(wrap) wrap[0]
#define WRAP_COUNT_VA_ARGS_2(wrap) wrap[0], wrap[1]
...
#define WRAP_COUNT_VA_COUNT_ARGS(wrap, ...) JOIN(WRAP_COUNT_VA_ARGS_, COUNT_VA_ARGS(__VA_ARGS))(wrap)
调用WRAP_COUNT_VA_COUNT_ARGS(args, int, A, float, B) 应该生成args[0], args[1]
把它们放在一起
触发警告:这会很糟糕
#define DECLARE_FUNCTION(name, ...) \
void name(__VA_ARGS__) { \
JOIN(name, _PROXY)((Variant[COUNT_VA_ARGS(__VA_ARGS__)+1]) {WRAP_VA_ARGS(Variant,__VA_ARGS__), Variant()}); \
} \
void JOIN(name, _PROXY)(const Variant (&args)[COUNT_VA_ARGS(__VA_ARGS__) + 1]) { \
JOIN(name, _HANDLER)(WRAP_COUNT_VA_COUNT_ARGS(args, __VA_ARGS__)); \
} \
void JOIN(name, _HANDLER)(__VA_ARGS__) { \
\
}
如果运气好的话,DECLARE_FUNCTION(myFunction, int, A, int, B, char, C) 的示例应该会产生:
void myFunction(int A, int B, char C) {
myFunction_PROXY((Variant[3+1]{Variant(A), Variant(B), Variant(C), Variant()});
}
void myFunction_PROXY(const Variant (&args)[3+1]) {
myFunction_HANDLER(args[0], args[1], args[2]);
}
void myFunction_HANDLER(int A, int B, char C) {
}
注意:数组是由常量表达式3 + 1创建的,因为我们需要做这个算术来解释myFunction_PROXY调用结束时的Variant()
不要做宏。宏很糟糕,嗯嗯?