一,lambda表达式
1.lambda表达式简介
2 lambda表达式的五个部分
1.捕捉列表capture–list:[ ] 这个部分是lambda表达式不可缺少的一个部分,也正是这一部分让我们的lambda表达式成为了lambda表达式。
2.参数parameters:这个部分是lambda表达式中可要可不要的一个部分。
3.mutable:这个东西相当于一个关键字,因为lambda表达式的参数的属性默认是const的,使用这个mutable能够解除掉lambda表达式的const属性。
3.lambda表达式的使用
3.[=]:以传值的方式捕捉所有在lambda父作用域内的变量。
4.[&]:以传引用的方式捕捉所有父作用域内的变量。
示例:
1,
//1,[val]传值方式 int main() { int i = 0, j = 0; cout << "adress:" << &i << " " << &j << endl<<endl; auto f1 = [i, j] {cout << "adress:" << &i << " " << &j << endl << endl;}; f1(); return 0; } //
adress:006FF904 006FF8F8 adress:006FF8E8 006FF8EC
2,
//1,[&val]传引用方式 int main() { int i = 0, j = 0; cout << "adress:" << &i << " " << &j << endl<<endl; auto f1 = [&i, &j] {cout << "adress:" << &i << " " << &j << endl << endl;}; f1(); return 0; } //
adress:00BAFA08 00BAF9FC adress:00BAFA08 00BAF9FC
当然,这两者还可以搭配起来使用变成:auto f1 = [i, &j] {cout << “adress:” << &i << ” ” << &j << endl << endl;};这样的话,第一个i便是传值,第二个j便是传应用。
3,
//直接以传值的方式捕捉父作用域的变量 [=] int main() { int i = 0, j = 0; cout << "adress:" << &i << " " << &j << endl<<endl; auto f1 = [=] {cout << "adress:" << &i << " " << &j << endl << endl;}; f1(); return 0; }
结果:
adress:00F8FD8C 00F8FD80 adress:00F8FD70 00F8FD74
4,
//以传引用的方式捕捉所有的变量[&] int main() { int i = 0, j = 0; cout << "adress:" << &i << " " << &j << endl<<endl; auto f1 = [&] {cout << "adress:" << &i << " " << &j << endl << endl;}; f1(); return 0; }
结果:
adress:00B9F9D8 00B9F9CC adress:00B9F9D8 00B9F9CC
5,
第五种方式便是捕捉this指针,this指针在哪里呢?在类里面。所以捕捉this指针的使用场景便是在类里面使用的。
class A { public: void func() { auto f2 = [a1,a2] {cout << "a1:" << a1 << " " << "a2:" << " " << a2;}; } private: int a1 = 1; int a2 = 2; };
原因在于lambda表达式的父作用域是func的函数体,a1,a2不在这个父作用域里面。在这个啥时候就得使用捕捉this指针的方式解决问题了:
class A { public: void func() { auto f2 = [this] {cout << "a1:" << a1 << " " << "a2:" << " " << a2;}; } private: int a1 = 1; int a2 = 2; };
使用:
class A { public: void func() { auto f2 = [this] {cout << "a1:" << a1 << " " << "a2:" << " " << a2;}; f2(); } private: int a1 = 1; int a2 = 2; }; int main() { A a; a.func(); return 0; }
结果:
a1:1 a2: 2
4.lambda表达式的类型
使用typeid(函数名/变量名).name()便可以知道一个lambda表达式的类型,实验如下:
int main() { auto f1 = [] {}; auto f2 = [] {}; cout << typeid(f1).name() << endl << endl; cout << typeid(f2).name() << endl << endl; return 0; }
class <lambda_d4e7b29f43988cb7e0ced57656dd48f2> class <lambda_5e6719a5fcb7a4e6979dcea7af21cec0>
可以看到这两个lambda表达式的类型都是奇怪的东西,都是一个class加上一个lambda+一串数字。这串数字其实是一个UUID。UUID是啥呢?百度如下:
这个UUID表示的是一个唯一通识码。其实在查完以后我还是对此并不了解,但是我可以告诉你在lambda表达式里面如果这两个lambda表达式的UUID不一样,那这两个lambda表达式的类型也是不一样的。所以因为类型不同,于是f1和f2也是不可以相互赋值的。(不同的lambda表达式不能相互赋值)如果赋值便会报错:
5,lambda表达式的本质
lambzda表达式的本质其实就是一个仿函数。何以见得呢?这两个万一完全不一样啊?仿函数是在一个类里面实现一个operator(),但是lambda表达式却是一个[]{}的表达式,这两个看起来毫不相干的东西怎么能使一个玩意呢?在这个时候就要透过现象看本质了,拉出汇编代码:
struct com//仿函数 { public: bool operator()(int a,int b) { return a > b; } }; int main() { int i = 0, j = 1; auto f1 = [i, j](int i,int j) {return i > j;}; f1(i, j);//调用lambda表达式 com Com; Com(i, j);//调用仿函数 return 0; }
仿函数:
lambda表达式:
二,function包装器
1,function简介
在这里先介绍一下function包装器的,首先function包装器是定义在头文件functional内的。function包装器是用来包装可调用对象的。这里的可调用对象包括:
1.函数指针 2.仿函数 3.lambda表达式。
2.为什么要包装可调用对象
3.使用
包装器的使用:function<return_type(Parameter type)>
使用场景如下:
1.逆波兰表达式的普通写法
class Solution { public: int evalRPN(vector<string>& tokens) { stack<int>st; for(int i = 0;i<tokens.size();i++) { if(tokens[i]=="+"||tokens[i]=="-"||tokens[i]=="*"||tokens[i]=="/") { int right = st.top(); st.pop(); int left = st.top(); st.pop(); if(tokens[i]=="+") { st.push(left+right); } if(tokens[i]=="-") { st.push(left-right); } if(tokens[i]=="*") { st.push(left*right); } if(tokens[i]=="/") { st.push(left/right); } } else { st.push(stoi(tokens[i])); } } return st.top(); } }; 控制台
class Solution { public: int evalRPN(vector<string>& tokens) { stack<int> st; map<string, function<int(int, int)>> hash = { {"+", [](int x, int y)->int{return x + y;}}, {"-", [](int x, int y)->int{return x - y;}}, {"*", [](int x, int y)->int{return x * y;}}, {"/", [](int x, int y)->int{return x / y;}}, }; for(auto& e : tokens) { if(hash.count(e) == 0) { st.push(stoi(e)); } else { int right = st.top(); st.pop(); int left = st.top(); st.pop(); st.push(hash[e](left, right)); } } return st.top(); } };
三,bind绑定器
bind绑定器的作用有两个,一个是调整参数的顺序,一个是调整参数的个数。在这两个作用中,其实有用的是第二个。接下来看看代码实例:
1.调换参数顺序
int Sub(int x, int y) { return x - y; } int main() { function<int(int, int)> f1 = bind(Sub,placeholders::_2, placeholders::_1);//传入的第一个参数给第二位,第二个参数给第一位 cout<<f1(10, 5)<<endl<<endl; return 0; }
结果:
-5
2.减少调用参数
成员函数内有this*类型的参数,每次传参时为了匹配类型都要传入this*类型的参数。为了减少这种操作便可以将plus()绑死减少传参时的麻烦!!!
class Plus { public: int Add(int x, int y) { return x + y; } }; int main() { function<int(int, int)> f2 = bind(&Plus::Add,Plus(), placeholders::_1, placeholders::_2); cout << f2(1, 5) << endl; return 0; }
原文地址:https://blog.csdn.net/qq_41934502/article/details/134782934
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.7code.cn/show_49228.html
如若内容造成侵权/违法违规/事实不符,请联系代码007邮箱:suwngjj01@126.com进行投诉反馈,一经查实,立即删除!