如何对C/C++的DECLARE_SOMETHING宏进行柯里化,实现分两步调用
实现柯里化的宏调用 CURRIED_DECLARE_SOMETHING(X)(Y)
如果要在C预处理阶段实现柯里化的宏,让CURRIED_DECLARE_SOMETHING(X)(Y)最终展开成{X, Y},可以利用宏的嵌套和临时宏定义技巧。以下是可行的实现:
// 辅助宏:负责最终生成 {X, Y} #define _COMBINE_DECLARE(X, Y) {X, Y} // 柯里化核心宏:第一步绑定X,返回一个能接受Y的临时宏 #define CURRIED_DECLARE_SOMETHING(X) \ #define _CURRY_TEMP(Y) _COMBINE_DECLARE(X, Y); \ _CURRY_TEMP // 示例用法 struct MyStruct { int a; int b; }; struct MyStruct s1 = CURRIED_DECLARE_SOMETHING(10)(20); // 展开后等价于 {10, 20}
工作原理
- 当你调用
CURRIED_DECLARE_SOMETHING(10)时,预处理阶段会先定义一个临时宏_CURRY_TEMP(Y),这个宏的作用是把绑定好的10和传入的Y传递给_COMBINE_DECLARE,生成{10, Y}。 - 紧接着返回这个临时宏
_CURRY_TEMP,后面的(20)就会调用_CURRY_TEMP(20),最终展开成{10, 20}。
不过这个方案有个小限制:临时宏_CURRY_TEMP是全局的,如果在同一个作用域内连续多次调用柯里化宏,后面的定义会覆盖前面的。如果需要避免这个问题,可以用C++的lambda实现更安全的运行时柯里化:
C++ 更优雅的方案(推荐)
如果是在C++环境下,用lambda表达式实现柯里化会更简洁且无全局宏冲突问题,同样能达到声明初始化的效果:
#include <utility> // 可选,用std::pair的话需要 // 柯里化宏,返回一个lambda,接受Y后返回 {X, Y} 复合字面量或pair #define CURRIED_DECLARE_SOMETHING(X) \ [=](auto Y) { return std::make_pair(X, Y); } // 或者直接返回 {X, Y} 用于结构体初始化 // 示例用法 #include <iostream> int main() { auto pair = CURRIED_DECLARE_SOMETHING(5)(7); // pair<int, int> 类型,值为(5,7) std::cout << pair.first << ", " << pair.second << std::endl; // 用于结构体初始化 struct MyStruct { int a; int b; }; MyStruct s = CURRIED_DECLARE_SOMETHING(10)(20)(); // 注意这里需要加()调用lambda,返回{10,20} std::cout << s.a << ", " << s.b << std::endl; }
说明
- lambda会捕获
X的值,返回一个可调用对象,当传入Y时会生成包含X和Y的pair或结构体字面量。 - 如果要直接初始化结构体,lambda需要返回
{X,Y},此时调用时需要加()来获取初始化表达式,比如CURRIED_DECLARE_SOMETHING(10)(20)()会返回{10,20}。
解决你尝试过的 CURRY(BODY, Y) 写法问题
你之前尝试的#define CURRY(BODY, Y) BODY(Y)思路是对的,但需要先让CURRIED_DECLARE_SOMETHING(X)生成一个带Y占位符的BODY。比如可以调整为:
#define _BODY(X) (Y) {X, Y} #define CURRY(BODY, Y) BODY(Y) #define CURRIED_DECLARE_SOMETHING(X) _BODY(X) // 调用方式:CURRY(CURRIED_DECLARE_SOMETHING(10), 20) → {10,20}
不过这种写法需要用CURRY来包裹两次调用,不如前面的CURRIED_DECLARE_SOMETHING(X)(Y)直观,但核心思路是通过_BODY(X)生成一个等待Y的模板,再用CURRY填充Y。
内容的提问来源于stack exchange,提问作者Lærne
相关产品推荐
相关产品推荐

