带捕获的lambda不能转换成函数指针

本文探讨了在C++中,为什么带捕获的lambda不能转换为函数指针,通过分析libuv库的回调机制和编译错误,解释了不带捕获和带捕获的lambda在汇编层面的调用差异,并揭示了lambda作为回调函数的原理。
摘要由CSDN通过智能技术生成

最近在看libuv(一个纯C实现的多平台异步io库)的相关东西,里面有许多回调函数。例如:

int uv_listen(uv_stream_t *stream, int backlog, uv_connection_cb cb)
Start listening for incoming connections. backlog indicates the number of connections the kernel might queue, same as listen(2). When a new incoming connection is received the uv_connection_cb callback is called.

typedef void (*uv_connection_cb)(uv_stream_t *server, int status)
Callback called when a stream server has received an incoming connection. The user can accept the connection by calling uv_accept(). status will be 0 in case of success, < 0 otherwise.

uv_listen函数监听的端口有事件到来的时候,会主动调用一个uv_connection_cb类型的回调函数,不过当时的需求是在调用uv_listen方法的时候有一个对象需要传递到回调uv_connection_cb回调中去(后来才知道,所有的handle对象都有一个data成员,可以通过这个东西传递),所以第一个想到的方法是使用带捕获的lambda额外增加一个参数,不过会报一个编译错。为了分析编译错原因,简单写了一段代码,方便观察原因。

// lambda.cpp 
#include <iostream> 

typedef void (*func)(int arg); 

void test_func(int arg1, int arg2, int arg3) 
{
    std::cout << arg1 << arg2 << arg3 << std::endl; 
}

void call_test_func(func fa) 
{
    int call_arg = 5; 
    fa(call_arg); 
}

int main(int argc, char* argv[]) 
{
    int main_arg1 = 1; 
    int main_arg2 = 2; 
    int main_arg3 = 3; 

    auto lam1 = [](int arg1, int arg2, int arg3)->void{test_func(arg1, arg2, arg3);}; 
    auto lam2 = [main_arg1, main_arg2](int arg3)->void{test_func(main_arg1, main_arg2, arg3);}; 
    
    lam1(main_arg1, main_arg2, main_arg3); 
    lam2(main_arg3); 

    // call_test_func(lam2); 
    
    // auto lam = [](int arg1)->void{ std::cout << arg1 << std::endl; };
    // lam(0); 
    // call_test_func(lam); 

    return 0; 
}

代码很简单,定义了两个函数test_funccall_test_func,不过call_test_func的参数是一个接受一个整数参数无返回值的函数指针。和我在调用libuv方法时遇到的情景类似,而后我刚开始想到的解决办法是利用lambda的捕获构造一个接受一个整数的对象,而后利用捕获将main中的对象带到回调中。不过会报一个编译错(把注释掉的那行call_test_func(lam2)恢复)。编译错如下:
编译错
和编译libuv时报的错类似,不能把某个类型的lambda转换为某种形式的指针。
so,先注释掉那行代码然后看一下调用带捕获的lambda和不带捕获的lambda的汇编码的差别:

g++ lambda.cpp -m32 -c 
objdump -d lambda.o 

-m32是将lambda.cpp编译成32为程序,需要先下载32位的开发环境。接着看汇编内容:

<main>
000000ac <main>:
  ac:   8d 4c 24 04             lea    0x4(%esp),%ecx
  b0:   83 e4 f0                and    
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值