论C++的lambda是函数还是对象
作者:51CTO技术 发布时间:2022-09-24 05:16:06
标签:C++,lambda
先说结论:
对于有捕获的
lambda
,其等价于对象。对于没有任何捕获的
lambda
,其等价于函数!
首先,很多C++程序员从lambda
用法上反推容易发现是对象,因为lambda可以捕获!这是函数做不到的。的确,比如:
int n = 100;
auto foo = [n](int a) {
return a > n;
};
cout<< foo(99);
如果编译器要实现foo
,大致类比这种写法(可能真实的实现细节不是这样,但思路类似)∶
struct Foo {
Foo(int i) {n=i;}
bool operator()(int a) {
return a > n;
}
private:
int n;
};
...
int n = 100;
Foo foo(n);
cout<< foo(99);
如果是引用捕获了变量,那么struct内有一个指针成员持有被引用捕获的变量的地址。
比如:
set<int> ns = {100, 200, 300};
auto foo = [&ns](int a) {
return ns.find(a);
};
cout<< foo(99);
大致等价于:
struct Foo {
Foo(set<int>* p) {p_ns = p;}
bool operator()(int a) {
auto &ns = *p-ns;
return ns.find(a);
}
private:
set<int>* p_ns;
};
...
set<int> ns = {100, 200, 300};
Foo foo(&ns);
cout<< foo(99);
然而……这并不是全部!
在没有捕获任何东西的时候,lambda
其实是等价于普通的函数的!可以用Linux C中函数pthread_create()来验证!它只能接收一个参数是void*,返回值也是void*的回调函数。
神奇的是,无参的lambda
也可以被pthread_create()
使用!
using namespace std;
struct A {
void* operator()(void*) {
cout<<"xxxx"<<endl;
return nullptr;
}
};
int main() {
A a;
a(NULL);
pthread_t t;
//pthread_create(&t, NULL, a, NULL); // 编译失败
auto cb = [](void*)->void* {
cout<<"xxxx"<<endl;
return nullptr;
};
pthread_create(&t, NULL, cb, NULL); // 编译通过
pthread_join(t, NULL);
return 0;
}
上面代码还可以再改一下,让cb去捕获一个变量, 比如:
auto cb = [&](void*)->void* {
cout<<"xxxx"<<endl;
return nullptr;
};
pthread_create(&t, NULL, cb, NULL);
这时,给pthread_create()传入cb同样会编译失败!错误信息:
cb.cpp: In function ‘int main()':
cb.cpp:23:30: error: cannot convert ‘main()::<lambda(void*)>' to ‘void* (*)(void*)'
23 | pthread_create(&t, NULL, cb, NULL);
| ^~
| |
| main()::<lambda(void*)>
In file included from /usr/include/x86_64-linux-gnu/c++/9/bits/gthr-default.h:35,
from /usr/include/x86_64-linux-gnu/c++/9/bits/gthr.h:148,
from /usr/include/c++/9/ext/atomicity.h:35,
from /usr/include/c++/9/bits/ios_base.h:39,
from /usr/include/c++/9/ios:42,
from /usr/include/c++/9/ostream:38,
from /usr/include/c++/9/iostream:39,
from cb.cpp:1:
/usr/include/pthread.h:200:15: note: initializing argument 3 of ‘int pthread_create(pthread_t*, const pthread_attr_t*, void* (*)(void*), void*)'
200 | void *(*__start_routine) (void *),
| ~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~
这其实也不难理解,C++在lambda的设计上也贯彻着零开销 (Zero Overhead)原则,也就是C++不在性能上干多余的事,显然函数比对象开销更小。所以即使同为lambda,在有无捕获的时候,其底层实现其实是截然不同的!
来源:https://developer.51cto.com/article/701352.html


猜你喜欢
- 一、Servlet3.0异步请求@WebServlet(value = "/async", asyncSupported
- 本文实例为大家分享了Java模拟HTTP Get Post请求,校园BBS自动回帖功能,供大家参考,具体内容如下设计思路找到帖子链接的集合,
- 前面做了app微信支付的回调处理,现在需要做微信公众号的支付,花了一天多时间,终于折腾出来了!鉴于坑爹的微信官方没有提供Java版的demo
- MD5加密简介哈希算法又称散列算法,是将任何数据转换成固定长度的算法的统称。 从本质上讲,MD5也是一种哈希算法,其输出是生成12
- 先说能用的究极解决方案,大家着急的直接复制走,以后想了解再过来看没有header,且所有Item的高度一致private fun getSc
- 前言最近项目中需要与andorid端进行交互,采用了MQTT消息进行通信,生产环境中偶尔会出现Too many publishesin pr
- Author:jeffreyDate:2019-04-08一、开发环境:1、mysql - 5.72、navicat(mysql客户端管理工
- idea 很强大,但是初次安装默认的有很多设置并不是满足我们开发的需要。以前经常一安装就要捣鼓很久,为此吐血整理初次安装设置一、切换主题(配
- 前言但是没有合理的架构,大家写出来的代码很可能是一大堆的复制粘贴。比如十几个页面,都有这个关注按钮。然后,你是不是也要写十几个地方呢 然后修
- 今天因为工作需要,把以前编写的一个GPS测试程序拿出来重新修改了一下。这个程序说起来有些历史了,是我11年编写的,那时候学了Android开
- 手机号登录在现在的项目中用的场景非常多,实现起来也不难,今天我们就一起来通过演示实现登录过程。 一、首先需要注册个第三方的账户,比
- 依赖<dependency> <groupId>io.springfox</groupId> <a
- Spring是一个开放源代码的设计层面框架,他解决的是业务逻辑层和其他各层的松耦合问题,因此它将面向接口的编程思想贯穿整个系统应用。Spri
- 一,内部类访问成员1,内部类可以直接访问外部类的成员,包括私有。2,外部类要访问内部类,必须建立内部类对象。class Outer{int
- 本文实例讲述了JAVA中的final关键字用法。分享给大家供大家参考,具体如下:根据上下文环境,java的关键字final也存在着细微的区别
- IO流基本概念IO流用来处理设备之间的数据传输Java对数据的操作是通过流的方式Java用于操作流的对象都是在IO包上流按操作数
- 可以使用System.ServiceProcess.ServiceController这个类允许连接到正在运行或者已停止的服务、对其进行操作
- /// <summary> /// 删除掉空
- 就我们所知道的,java中有子类和父类,子类由于继承父类而形成,那么父类还有没有父类呢?答案是有了,父类的父类就是object类,一切父类都
- 案例说明:使用Java实现简单的斗地主洗牌发牌的操作;具体规则:共有54张牌,顺序打乱;三个玩家参与游戏,三人交替摸牌,每人17张牌,最后留