在C中模拟lambda表达式的优雅方式

时间:2014-08-28 09:12:25

标签: c lambda

让我们考虑一下C程序的场景:

RESPONSE_CALLBACK_T response_callback = &response_callback_function;
SendRequest(param1, param2, response_callback);

SendRequest函数可以在网络服务器上发布一些数据,或者调用一些其他程序模块,这些模块应该在完成工作后触发回调。因此,在调用此函数时,我们需要指定一个指向我们定义的回调函数的指针。

是否有优雅编写此代码的方式类似于支持lambda表达式的高级OPP语言,例如:

SendRequest(param1, param2, function(int responseCode) { print(responseCode) });

我怎样才能最好地模拟这种行为?

1 个答案:

答案 0 :(得分:3)

在标准C中,无法提供函数文字;函数指针必须指向顶级函数。也没有办法捕获未作为参数传递的局部变量。

但是,为了增加(所谓的)优雅和降低可持续性(并且可能还会降低可靠性):

在您的示例中,您不需要中间变量response_callback。在C中,typedef只是类型的别名,如果函数的签名与RESPONSE_CALLBACK的签名匹配,则可以直接使用函数的名称:

SendRequest(param1, param2, response_callback_function);

对于函数指针,您也不需要&运算符。我发现C的优雅标准足够优雅。

一些编译器,例如gcc,实现嵌套函数,允许您在函数附近定义函数:

if (print_flag) {
    void func(int rc) { print(rc); }

    SendRequest(param1, param2, func);
}

嵌套函数与statement expressions一起使用,也是仅some compilers支持的非标准扩展程序,可用于write a lambda macro。我没有发现该网站上显示的宏特别优雅,但如果你有回调类,例如事件处理程序,您可以简化宏(如果您愿意在整个过程中使用相同的硬编码参数名称):

#define handler(l_body) \
  ({ void l_anonymous(int rc) l_body l_anonymous; })

并称之为:

SendRequest(param1, param2, handler({ print(rc); }));

(您可以将花括号作为宏的一部分,但回调语句后面的分号看起来很奇怪;我更喜欢大括号在客户端代码中。)

注意这似乎是发生工作的功能,而不是设计工作的功能。并且您不应该将封闭函数的任何局部变量用于在这些变量的生命周期结束时可能调用的回调。 (它会编译,但会导致运行时错误。)请仔细进行。

有些编译器可能有真正的lambdas或函数文字的扩展名,但我不知道。