我读过这篇文章,它说明了如何__VA_OPT__使用函数宏来递归扩展宏。我想实现类似的东西,不同之处在于宏是在嵌套上下文中扩展的。
输入:
NEST_RECURSIVE(A, B, C)
Run Code Online (Sandbox Code Playgroud)
应该产生(顺序无关):
((( | C) | B) | A)
Run Code Online (Sandbox Code Playgroud)
我的方法稍微概括了这篇文章:
#define PARENS ()
#define EXPAND(...) EXPAND4(EXPAND4(EXPAND4(EXPAND4(__VA_ARGS__))))
#define EXPAND4(...) EXPAND3(EXPAND3(EXPAND3(EXPAND3(__VA_ARGS__))))
#define EXPAND3(...) EXPAND2(EXPAND2(EXPAND2(EXPAND2(__VA_ARGS__))))
#define EXPAND2(...) EXPAND1(EXPAND1(EXPAND1(EXPAND1(__VA_ARGS__))))
#define EXPAND1(...) __VA_ARGS__
#define FOR_EACH_R(func, ...) __VA_OPT__(EXPAND(FOR_EACH_HELPER_R(func, __VA_ARGS__)))
#define FOR_EACH_HELPER_R(func, sub, ...) func(__VA_OPT__(FOR_EACH_AGAIN_R PARENS (func, __VA_ARGS__)), sub)
#define FOR_EACH_AGAIN_R() FOR_EACH_HELPER_R
#define MY_FUNC(nested, var) (nested | var)
#define NEST_RECURSIVE(...) FOR_EACH_R(MY_FUNC, __VA_ARGS__)
Run Code Online (Sandbox Code Playgroud)
当前代码产生以下输出:
(FOR_EACH_HELPER_R (MY_FUNC, B, C) | A)
Run Code Online (Sandbox Code Playgroud)
可以看出,扩展不会发生在第一级之后。
我想我必须EXPAND别的地方,但是,我不知道在哪里。
我想要做的事情完全有可能是不可能的,但是,C++20 之前的递归宏扩展方法(利用PP_NARG)确实适用于嵌套,所以我希望新的、更干净的方法可以使用它还有!
在 C 语言中,我习惯于:
if (ELEM(value, a, b, c)) { ... }
Run Code Online (Sandbox Code Playgroud)
这是一个具有可变数量参数的宏,以避免输入
if (value == a || value == b || value == c) { ... }
Run Code Online (Sandbox Code Playgroud)
C 示例可以在与 C 一起使用的 Varargs `ELEM` 宏中看到。
这在 Rust 中可能吗?我认为它会使用match. 如果是这样,如何使用可变参数来实现这一目标?
我想要一个macro声明int一个给定名称和可选的初始化表达式.
我尝试在Stack Overflow上使用这个答案,但没有成功.
这是我试过的:
#define macro(...) int FIRST(__VA_ARGS__)(REST(__VA_ARGS__))
Run Code Online (Sandbox Code Playgroud)
这样使用时没有问题:
macro(foo);
Run Code Online (Sandbox Code Playgroud)
但是当给出初始化器时会出现错误:
macro(foo, 42);
Run Code Online (Sandbox Code Playgroud)
另一种 - 只是使用时会在没有参数的情况下__VA_ARGS__从-pedanticGCC 发出警告.
我怎样才能解决这个问题?
()当没有初始化表达式时,是否也可以避免括号 - 这意味着没有零初始化但是默认?
请注意,我的真实用例不仅适用int于任何类型,而且使用像boost这样的第三方也不是一种选择.
与例如 C++ 的可变参数模板相比,CPP(C/C++ 预处理器;为简单起见,我将在本问题中将其视为一种单独的语言)中的可变参数宏非常有限。本质上,可变参数宏只是带有参数的宏,其参数允许包含逗号。这没有提供计算参数、一个接一个操作参数等的直接方法。这些事情是可能的,但需要精心设计、令人困惑且编译缓慢的技巧,例如本问题中描述的技巧。唯一可以直接处理的事情VA_ARGS就是将它们传递给可变参数函数。
我的问题是,他们为什么要这样设计?在像 CPP 这样的任何纯函数式语言中,列表的标准方法是 cons 样式的模式匹配:处理列表的第一个参数并递归其余部分,并为空列表设置基本情况。标准委员会成员应该非常熟悉这种方法。
为什么 CPP 的可变参数宏没有采用这样的方法?可变参数宏是否只是一种包装可变参数函数的方法,这样就不需要对参数列表进行操作?是否存在一些潜在的问题使得允许可变参数宏递归变得不切实际?或者...?
注意:我不是在寻找“因为人们不应该想要可变参数宏”形式的答案/评论。boost.preprocessor 之类的东西的存在表明,理性的人希望以非平凡的方式使用预处理器。也不寻求关于为什么其他设计是一个好/坏主意的个人意见。我试图找出当时的实际推理。
我想要做的是使用宏访问代码.但编译器给了我这个错误
标识符"BUTTON___button"未定义
#define BUTTON_1 HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_8)
#define BUTTON_2 HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_9)
#define BUTTON_3 HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_4)
#define BUTTON_4 HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_5)
#define BUTTON_5 HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_13)
#define BUTTON_6 HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_14)
#define BUTTON_7 HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_12)
#define BUTTON_8 HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_11)
#define BUTTON_9 HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_15)
#define BUTTON_10 HAL_GPIO_ReadPin(GPIOD, GPIO_PIN_0)
#define BUTTON_11 HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_10)
#define BUTTON_12 HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_15)
#define BUTTON_13 HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_1)
#define BUTTON_14 HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_2)
#define BUTTON_15 HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_11)
#define BUTTON_16 HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_2)
#define BUTTON_17 HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_0)
#define BUTTON_18 HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_1)
#define BUTTON_19 HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_5)
#define BUTTON_20 …Run Code Online (Sandbox Code Playgroud)