商城网站开发,dw做网站详细教程,人力资源公司名称大全简单大气,好用的在线地图网站仿函数的最大缺点是#xff1a;
如果命名不合规范并且没有给出注释#xff0c;直接阅读难以理解#xff08;排序的调用过程中#xff0c;不查看仿函数细节#xff0c;则很难直接得知是升序排序还是降序排序#xff09;每次实现仿函数都需自己构建一个类
因此C从其他语言…仿函数的最大缺点是
如果命名不合规范并且没有给出注释直接阅读难以理解排序的调用过程中不查看仿函数细节则很难直接得知是升序排序还是降序排序每次实现仿函数都需自己构建一个类
因此C从其他语言借鉴了lambda表达式语法让我们可以无需提前创建类提高代码可读性。
1.lambda表达式的语法
lambda表达式的格式为[capture-list](parameters)mutable-return-type{statement}
capture-list捕捉列表编译器识别[]判定是否为lambda函数因此[]不可省略。而捕捉列表本身可以根据父域对于lambda函数内的变量来说的父域的上下文获取变量供lambde函数使用parameters参数列表和函数的参数列表基本一致可以为空mutable这是一个关键字意思为“可变的/易变的”默认情况下lambda函数总是类似const函数的行为除非使用引用捕捉就不会有const行为而使用该关键字可以取消const行为并且参数列表此时不能忽略return-type返回值类型和普通函数基本类似没有返回值时可以省略若返回值明确也会自动推导也可以省略statement函数体内部可以使用参数列表中的参数和捕获的变量列表
在lambda函数定义中也具有函数签名的特征并且参数列表和返回值类型是可选部分而捕捉列表和函数体可以为空。
因此最简单的lambda函数为[]{}这个lambda函数不能做任何事情。
2.lambda表达式的运用
让我们尝试使用lambda表达式来书写一个Add()。
#include iostream
using namespace std;
int main()
{auto add [](int x, int y)-int { return x y; };//整体代表一个 lambda 对象cout [](int x, int y)-int { return x y; }(1, 2) endl;cout add(1, 2) endl;return 0;
}而使用lambda表达式就可以替代仿函数在sort()中的使用
#include iostream
#include Date.hpp //以前写的 Date 类
using namespace std;
int main()
{vectorDate v { { 2013, 7, 9 }, { 2022, 6, 5 }, { 2023, 4, 17 } };auto less [](const Date d1, const Date d2)-bool { return d1 d2; };sort(v.begin(), v.end(), less);return 0;
}那捕捉列表怎么用呢假设我们需要一个交换函数使用lambda有两种方式书写。
#include iostream
using namespace std;
int main()
{//1.设置用于交换的数int x 10, y 5;cout x x y y \n;//2.用于交换的 lambda 表达式指针参数版auto swap1 [](int* px, int* py){int tmp *px;*px *py;*py tmp;};swap1(x, y);cout x x y y \n;//3.用于交换的 lambda 表达式引用参数版auto swap2 [](int rx, int ry){int tmp rx;rx ry;ry tmp;};swap2(x, y);cout x x y y \n;//4.用于交换的 lambda 表达式列表捕捉版auto swap3 [x, y](){int temp x;x y;y temp;};swap3();cout x x y y \n;return 0;
}而捕捉列表可以有多种语法形式来捕捉
//特定
auto func1 [x, y](){};//对应变量传值捕捉
auto func2 [x, y](){};//对应变量引用捕捉需要注意不要误认为是取地址
auto func3 [x, y](){};//对应变量引用对应变量传值混合捕捉//泛指
auto func4 [](){};//所有变量均可引用捕捉包括 this
auto func5 [](){};//所有变量均可传值捕捉包括 this
auto func6 [, x](){};//除了 x 参数是传值捕捉其他都是引用捕捉
auto func7 [this](){};//捕获当前的 this 指针3.lambda表达式的误解 lambda表达式的捕获列表只能捕获父域的变量如果在父域内没有对应的变量则会编译报错。注意这个父域是对于lambda内部的来说的包含lambda表达式所处的表达式 #include iostream
using namespace std;
int main()
{//交换int x 10, y 5;cout x x y y \n;do {do {auto swap [x, y](){int temp x;x y;y temp;};swap();} while (0);} while (0);cout x x y y \n;return 0;
}lambda表达式产生的lambda对象不允许相互赋值这涉及到底层实现不同的或者说哪怕相同的lambda表达式结构生成的对象的类型均不一样并且在不同编译器上运行都不一样有些编译器的实时可能会看不出来 #include iostream
using namespace std;
int main()
{//交换int x 10, y 5;auto swap1 [x, y](){int temp x;x y;y temp;};auto swap2 [x, y](){int temp x;x y;y temp;};cout typeid(swap1).name() \n;cout typeid(swap2).name() \n;//swap1 swap2; //报错return 0;
}lambda对象虽然不允许赋值但是允许拷贝构造出一个新副本 #include iostream
using namespace std;
int main()
{//交换int x 10, y 5;auto swap [x, y](){int temp x;x y;y temp;};auto swapCopy(swap);cout typeid(swap).name() \n;cout typeid(swapCopy).name() \n;return 0;
}可以将lambda表达式赋值给和lambda返回值相同类型的函数指针但是带有捕捉列表的lambda表达式不允许这么做 #include iostream
using namespace std;
void(*p)(int, int);
int main()
{//交换int x 10, y 5;auto swap [](int x, int y){cout x x \n;cout y y \n;};p swap;(*p)(x, y);return 0;
}#include iostream
using namespace std;int main()
{//交换int x 10, y 5;//lambda表达式没有捕获列表可以直接赋值给函数指针auto func1 []() { cout Hello, World! endl; };void(*ptr1)() func1;ptr1(); //输出Hello, World!//lambda表达式带有捕获列表无法直接赋值给函数指针//int(*ptr2)() [x, y]() { return x y; }; //编译错误return 0;
}如果是引用捕捉无需使用关键字mutable也可以在lambda表达式内修改。也就是说捕捉变量实际上是一个变量拷贝了父域的变量而引用则直接使用该变量不过如果一个是引用捕捉一个传值引用就还是需要加上mutable #include iostream
using namespace std;
int main()
{//交换int x 10, y 5;//auto func [x, y]()// {// x 0;// y 0;//出错不允许改变// };auto func [x, y]()mutable //必须使用 mutable{x 0;y 0;//只是改变了局部变量};func();cout x x endl; //输出 x 0cout y y endl; //输出 y 5return 0;
}this的传值可以让lambda表达式成为类似成员函数的存在写入类中 #include iostream
using namespace std;class Data
{
public:void function(){auto func [this](){cout x x , y y \n;x 100;y 500;cout x x , y y \n;};func();}private:int x 10;int y 50;
};
int main()
{Data d;d.function();return 0;
}4.lambda表达式的疑问
我们的确可以使用lambda表达式解决了使用sort(v.begin(), v.end(), less)的问题但是我们还有一种情况会使用仿函数就是在使用map的时候会写出mapstring, int, 仿函数类类型对最后的仿函数需要将string转化为key但是仿函数的类型我们尚且可以知道那么lambda怎么办呢
lambda的类型比较难以获取并且还是匿名的尽管有些其他的办法获取类型但是我们更加推荐使用包装类function{}这些我们下一篇介绍。