joomla 做 企业网站,广告公司简介模板200字,wordpress adsense主题,网络广告类型有哪几种简介 用法
lambda表达式是c11引入的一个重要特性#xff0c;基本语法如下
[捕获列表](形参列表) - 返回类型 {// 函数体
}其中捕获列表和形参列表可以为空#xff0c;返回值类型大部分情况下可以忽略不写。 lambda表达式的结构整体上和普通函数一样#xff0c;特…简介 用法
lambda表达式是c11引入的一个重要特性基本语法如下
[捕获列表](形参列表) - 返回类型 {// 函数体
}其中捕获列表和形参列表可以为空返回值类型大部分情况下可以忽略不写。 lambda表达式的结构整体上和普通函数一样特殊在比普通函数多一个捕获列表。捕获列表的作用是获取作用域以外的局部变量给函数体使用。捕获器有两种形式
按值捕获语法[localValue]原理和形参列表的按值传递类似。按引用捕获语法[localValue]原理和形参列表的按引用传递类似。
举个例子
int main {int base 100;int count 0;auto trans [base, count](int value) {count;return base value;};int res trans(5);printf(base%d, count%d, res%d\n, base, count, res);
}示例代码中的lambda表达式trans按值捕获局部变量base、按引用捕获局部变量count因此lambda表达式内部修改base不会影响外部base的值而修改count则会影响外部count的值。
lambda表达式的原理
本质lambda本质上是函数对象函数对象的介绍见本文最后一节 扩展知识。 为了弄清楚lambda表达式的原理我们需要研究研究示例代码的汇编码
main::{lambda(int)#1}::operator()(int) const:push rbp...ret
main:push rbp...call main::{lambda(int)#1}::operator()(int) const...ret函数调用语句int res trans(5);对应的汇编码为call指令调用的函数符号main::{lambda(int)#1}::operator()(int)代表的是匿名类main::{lambda(int)#1}的函数调用操作符operator()。 函数操作符operator()这不是函数对象嘛为了一探究竟我们用函数对象重写示例代码对比两者的汇编码看看
int main() {int base 100;int count 0;// auto trans [base, count](int value) {// count;// return base value;// };struct TransLambda {TransLambda(int count) : _count(count) { }int operator()(int value) {_count;return _base value;}int _count;int _base;};TransLambda trans(count);int res trans(5);
}这段代码的汇编码如下
main::TransLambda::TransLambda(int) [base object constructor]:push rbp...ret
main::TransLambda::operator()(int):push rbp...ret
main:push rbp...call main::TransLambda::TransLambda(int) [complete object constructor]...call main::TransLambda::operator()(int)...leaveret对比lambda表达式版本和函数对象两个版本的汇编码发现两段汇编码的内容几乎一样。破案了lambda表达式就是函数对象也可以认为lambda是函数对象的语法糖。 为了进一步理解我们不妨大胆猜测一下编译器拿到lambda函数后做了几件事
定义匿名类main::{lambda(int)#1}。参考lambda表达式的内容重载main::{lambda(int)#1}的函数调用操作符operator()。为匿名类main::{lambda(int)#1}分配一个实例并赋值给变量trans。调用实例trans的函数调用操作符operator()。
所以lambda表达式实际上是语法更为简洁的函数对象它的特殊部分捕获列表实际上是传给函数对象的成员变量
按值捕获相当于按值传参函数对象持有的是这个变量的拷贝。按引用捕获相当于按引用传参函数对象持有的是这个变量的引用。捕获列表和形参列表的区别在于 捕获列表捕获到的变量由函数对象的成员变量维护生命周期于函数对象一样而形参列表的入参生命周期是函数级别的。
避坑指南
static修饰的lambda表达式不能按引用捕获局部变量。
例如
std::string GetString() {std::string id Test;static auto appendId [id](std::string value) {return name - value;};std::string res appendId(Hello);
}int main() {std::string res1 GetString();std::string res2 GetString(); // 可能引发奔溃
}原因很简单lambda表达式appendId按引用捕获局部变量id所以appendId会持有id的引用但是因为appendId是static修饰的所以生命周期比局部变量id长当id销毁以后appendId持有的id引用实际上已经销毁了出现未定义的行为。
其他坑待补充…
扩展知识
函数对象仿函数
函数对象也叫仿函数。如果一个类重载了函数调用操作符operator()这个类的实例就叫函数对象可以像使用函数一样使用这个对象。例如
Struct Transform {int operator()(int value) {count;return 100 value;}int count 0;
};int main() {Transform trans;int res trans(5);
}Transform的实例trans就是一个函数对象我们可以像调用函数一样使用trans。函数对象的特殊之处在于可以保持状态例如trans可以通过成员变量count统计自己被调用过多少次而普通函数做不到这一点。