使用宏“高阶函数”在 C 中进行函数式编程 发电机
请仔细注意,因为这是一个大问题;-)
我想在 C 中使用模板函数进行通用集合操作(如搜索、foreach 等),同时维护编译器静态类型检查。 当您使用简单的回调(如本示例中所示)时,这是相当简单的:
#define MAKE_FOREACH(TYPE)\
void foreach_##TYPE (TYPE[n] array, int n, void(*f)(TYPE)) {\
for(int i = 0; i < n; i++) {\
f(array[i]);\
}\
}
因此您可以执行以下操作:
MAKE_FOREACH(int)
MAKE_FOREACH(float)
void intcallback(int x){
printf("got %d\n", x);
}
void floatcallback(float x){
printf("got %f\n", x);
}
int main(){
int[5] iarray = {1,2,3,4,5};
float[5] farray = {1.0,2.0,3.0,4.0,5.0};
foreach_int(iarray, 5, intcallback);
foreach_float(farray, 5, floatcallback);
}
如果我想使用返回类型实现回调,例如创建一个“map”函数,我可以这样做:
#define MAKE_MAP(TYPE, RTYPE)\
RTYPE* map_##TYPE (TYPE[n] array, int n, RTYPE(*f)(TYPE)) {\
RTYPE* result = (RTYPE*)malloc(sizeof(RTYPE)*n);\
for(int i = 0; i < n; i++) {\
result[i]=f(array[i]);\
}\
}
所以远了,真好。 当我希望我的回调函数接受任意数量的类型化参数时,问题就来了。
这个想法是这样的:
#define MAKE_MAP(TYPE, RTYPE, ...)\
RTYPE* map_##TYPE (TYPE[n] array, int n, RTYPE(*f)(TYPE, __VA_ARGS__), __VA_ARGS__)
/*this would work for the declaration (because just the types would be enough)
but the parameter names are missing :-s*/ \
{\
RTYPE* result = (RTYPE*)malloc(sizeof(RTYPE)*n);\
for(int i = 0; i < n; i++) {\
result[i]=f(array[i], /*here the names of the parameters, in order*/);\
}\
}
所以,正如你所看到的,我可以将映射函数声明为:
MAKE_MAP(int, float, char)
给出:
float* map_int(int[n] array, int n, float(*f)(int, char), char);
但我无法弄清楚如何实现使用预处理器传递的参数。 在此,我请求您的帮助、想法和建议。
(顺便说一句,不要告诉我使用可变参数函数作为模板并将 va_list 参数传递给回调,因为所有这些都是因为类型检查:-p)
Pay attention carefully because this is a hell of a question ;-)
I want to use template functions for generic collection actions (like search, foreach, etc.) in C while maintaining compiler static type checking. It is fairly straightforward while you're using simple callbacks like in this example:
#define MAKE_FOREACH(TYPE)\
void foreach_##TYPE (TYPE[n] array, int n, void(*f)(TYPE)) {\
for(int i = 0; i < n; i++) {\
f(array[i]);\
}\
}
so you can do things like:
MAKE_FOREACH(int)
MAKE_FOREACH(float)
void intcallback(int x){
printf("got %d\n", x);
}
void floatcallback(float x){
printf("got %f\n", x);
}
int main(){
int[5] iarray = {1,2,3,4,5};
float[5] farray = {1.0,2.0,3.0,4.0,5.0};
foreach_int(iarray, 5, intcallback);
foreach_float(farray, 5, floatcallback);
}
If I'd like to implement callbacks with return types, for example to make a "map" function, I could do:
#define MAKE_MAP(TYPE, RTYPE)\
RTYPE* map_##TYPE (TYPE[n] array, int n, RTYPE(*f)(TYPE)) {\
RTYPE* result = (RTYPE*)malloc(sizeof(RTYPE)*n);\
for(int i = 0; i < n; i++) {\
result[i]=f(array[i]);\
}\
}
So far, so good. The problem comes now, when I want my callback functions to accept any number of typed arguments.
The idea is something like:
#define MAKE_MAP(TYPE, RTYPE, ...)\
RTYPE* map_##TYPE (TYPE[n] array, int n, RTYPE(*f)(TYPE, __VA_ARGS__), __VA_ARGS__)
/*this would work for the declaration (because just the types would be enough)
but the parameter names are missing :-s*/ \
{\
RTYPE* result = (RTYPE*)malloc(sizeof(RTYPE)*n);\
for(int i = 0; i < n; i++) {\
result[i]=f(array[i], /*here the names of the parameters, in order*/);\
}\
}
so, as you can see, I could declare a map function as:
MAKE_MAP(int, float, char)
giving:
float* map_int(int[n] array, int n, float(*f)(int, char), char);
but I cannot figure how to implement the parameter passing with the preprocessor. Here is where I ask for your help, ideas and suggestions.
(By the way, don't tell me to use a variadic function as template and passing a va_list argument to the callback, because all this stuff was because of the type checking :-p)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
如果您使用的是 Linux/BSD Unix,请查看 queue(3) 并检查
/usr/include/sys/queue.h
- 之前已经完成了:)If you are on Linux/BSD Unix, take a look at queue(3) and check into
/usr/include/sys/queue.h
- it's been done before :)最近的一个问题提出了很多问题无耻的预处理器滥用库。
A recent question raised quite a few shameless preprocessor abusing libraries.
作为参考,GCC 4.6 的源代码对向量实现了类似的技巧。 查看其文件
gcc/vec.h
For information, the source code of GCC 4.6 implements similar tricks for vectors. Look into its file
gcc/vec.h