您现在的位置是:亿华云 > 数据库
编译器如何实现lambda表达式?
亿华云2025-10-04 03:27:23【数据库】7人已围观
简介本文转载自微信公众号「程序喵大人」,作者程序喵大人。转载本文请联系程序喵大人公众号。lambda表达式在C++11中引入,用lambda表达式表示匿名函数非常方便,语法很简单,而且可以使代码更紧凑,更
本文转载自微信公众号「程序喵大人」,编译表达作者程序喵大人。器何转载本文请联系程序喵大人公众号。实现式
lambda表达式在C++11中引入,编译表达用lambda表达式表示匿名函数非常方便,器何语法很简单,实现式而且可以使代码更紧凑,编译表达更易于阅读。器何
lambda表达式更适合定义小点的实现式回调内联去传递给其他函数,而不是编译表达在其他地方定义个完整的函数对象,并在其重载函数调用运算符中实现回调逻辑。器何所有的实现式逻辑都在一个位置上,容易理解和维护,编译表达lambda表达式可以接收参数,器何可返回值,实现式可模板化,可通过值或引用的方式访问外面的变量,相当的灵活。
关于lambda表达式的使用,我之前介绍过,可以看这篇文章搞定c++11新特性std::function和lambda表达式,这里一笔带过:
auto lambda { []{ cout << "Hello \n"; } }; lambda();那这个lambda表达式是如何实现的呢?
编译器会将lambda表达式自动转换为函数对象,编译器会为此生成个唯一的命名。云南idc服务商上面的示例会自动的转换成下面这样的函数对象,注意函数调用运算符是个const方法,返回类型是auto,这方便编译器根据方法体自动推导出返回类型。
class CompilerGeneratedName { public: auto operator()() const { cout << "Hello \n"; } };编译器生成的lambda闭包名字会是一些奇怪的名子,例如__Lambda_21Za等,我们没法知道这个名字,我们也不需要知道这个名字。
lambda表达式可以接收参数,参数在圆括号之间指定,就像普通函数一样,下面是例子:
auto lambda { [](int value){ cout << "The value is " << value << endl; } }; lambda(42);如果lambda表达式不接收任何参数,可以指定空括号或者直接省略括号。
编译器会将上面的lambda表达式自动转换为下面这样:
class CompilerGeneratedName { public: auto operator()(int value) const { cout << "The value is " << value << endl; } };lambda表达式可以返回值,返回类型在箭头后面指定,称为尾返回类型,看代码:
auto lambda { [](int a, int b) -> { return a + b; } }; int sum = lambda(11, 22);编译器转成这样:
class CompilerGeneratedName { public: auto operator()(int a, int b) const { return a + b; } };那能捕获变量的lambda表达式是怎么实现的呢?
比如下面的lambda表达式:
double data { 1.234 }; auto lambda { [data]{ cout << "Data = " << data << endl; } }捕获的变量会变为lambda闭包的数据成员,源码库值捕获的变量被拷贝到仿函数的数据成员中,编译器的行为是这样:
class CompilerGeneratedName { public: CompilerGeneratedName(const double& d) : data { d } { } auto operator()() const { cout << "Data = " << data << endl; } private: double data; };还有泛型lambda表达式:
auto areEqual { [](const auto& value1, const auto& value2) { return value1 == value2; } }; vector values1 { 2, 5, 6, 9, 10, 1, 1 }; vector values2 { 4, 4, 2, 9, 0, 3, 1 }; findMatches(values1, values2, areEqual, printMatch);编译器会转换成这样:
class CompilerGeneratedName { public: template <typename T1, typename T2> auto operator()(const T1& value1, const T2& value2) const { return value1 == value2; } };如果findMatches()函数中的参数是其他类型,那么areEqual泛型表达式不需要任何更改就可以直接继续使用。
聊完了编译器怎么实现的lambda表达式,下面介绍下lambda表达式的捕获方式。
捕获方式
有两种方法从闭包作用域捕获所有变量,称为默认捕获:
[=] 值捕获所有变量 [&]引用捕获所有变量 注意: 使用引用方式捕获变量时,必须确保引用在lambda表达式执行期间是合法的。 当使用默认捕获时,通过值(=)或引用(&),只有那些在lambda 表达式中真正使用的变量才会被捕获,未使用的变量不会被捕获。 不建议使用默认捕获,即使默认捕获只捕获那些在lambda 表达式主体中真正使用的变量,通过使用=默认捕获,可能会意外的导致高代价的拷贝,通过使用&默认捕获,可能意外的源码下载在闭包作用域中修改变量,建议明确指定想要捕获哪些变量以及捕获方式。再注意:全局变量总是通过引用捕获,例如在下面的代码中,默认捕获用于按值捕获所有内容,然而全局变量global其实是通过引用捕获的,在执行lambda 后它的值被更改。
int global { 42 }; int main() { auto lambda { [=] { global = 2; } }; lambda(); // 这里global是2! }不允许像下面这样显式捕获全局变量,这样编译会失败:
auto lambda { [global] { global = 2; } }; // error所以,建议不要使用全局变量。
对于不捕获任何内容的lambda表达式,编译器自动提供转换运算符,将lambda 表达式转换为函数指针。这样的lambda表达式可作为参数传递给其他函数。
在C++20中关于lambda表达式也做了一些更新,可以模板化lambda表达式,也可以默认构造、拷贝和赋值lambda表达式,像下面这样:
auto lambda { [](int a, int b) { return a + b; } }; decltype(lambda) lambda2; // 默认构造 auto copy { lambda }; // 拷贝构造 copy = lambda2; // 拷贝赋值这不是本文的主题,就不过多介绍了。
很赞哦!(91718)
相关文章
- 以上的就是为大家介绍的关于域名的详解
- 如何购买已被注册的域名?
- 帮助克服病魔的五款免费或开源的医疗软件工具
- 过期域名抢注的方法
- 用户邮箱的静态密码可能已被钓鱼和同一密码泄露。在没有收到安全警报的情况下,用户在适当的时间内不能更改密码。在此期间,攻击者可以随意输入帐户。启用辅助身份验证后,如果攻击者无法获取移动电话动态密码,他将无法进行身份验证。这样,除非用户的电子邮件密码和手机同时被盗,否则攻击者很难破解用户的邮箱。
- 有哪些不同的CSS前端框架可供选择?
- 看完这篇还不懂 MySQL主从复制,可以回家躺平了~
- 微服务架构让你的应用程序开发提速!
- 4、企业无形资产:通用网站已成为企业网络知识产权的重要组成部分,属于企业的无形资产,也有助于提升企业的品牌形象和技术领先形象。它是企业品牌资产不可或缺的一部分。
- 聊聊 Linkerd Service Mesh 授权策略 (Server & ServerAuthorization)