【C++11】详解lambda!
一、lambda表达式语法1.lambda表达式本质是一个数对匿名函象跟普通函数不同的是它可以定义在函数内部。lambda表达式语法使用层而言没有类型所以我们一般是用auto或者模板参数定义的对象去接收lambda对象。2.lambda表达式的格式 [capture-list] (parameters)- return type {function body}3.[capture-list]:捕捉列表该列表总是出现在lambda函数的开始位置编译器根据[]来判断接下来的代码是否为lambda函数捕捉列表能够捕捉上下文中的变量供lambda函数使用捕捉列表可以传值和传引用捕捉。捕捉列表为空也不能省略。4.(parameters):参数列表与普通函数的参数列表功能类似如果不需要参数传递则可以连同一起省略。5.- return type返回值类型用追踪返回类型形式声明函数的返回值类型没有返回值此部分可省略。一般返回值类型明确的情况下也可省略由编译器对返回类型进行推导。6.{function body}函数体函数体内的实现跟普通函数完全类似在函数体内除了可以使用其参数外还可以使用所有捕获到的变量函数体为空也不能省略。//语法 int main() { auto add1 [](int x, int y)-int {return x y; }; cout add1(2, 3) endl; //1.捕捉列表为空也不能省略 //2.参数为空可以省略 //3.返回值可以省略它可以通过返回对象自动推导 //4.函数体不能省略 auto func1 [] { cout hello endl; return 0; }; func1(); int a 0, b 1; auto swap1 [](int x, int y) { int tmp x; x y; y tmp; }; swap1(a, b); cout a : b endl; return 0; }二、捕捉列表1.lambda表达式中默认只能用lambda函数体和参数中的变量如果想用外层作用域中的变量就需要进行捕捉2.第一种捕捉方式是在捕捉列表中显示的传值捕捉和传引用捕捉捕捉的多个变量用逗号分割。[x,y,z]表示x和y值捕捉z引用捕捉3.第二种捕捉方式是在捕捉列表中隐式捕捉我们在捕捉列表写一个表示隐式值捕捉写一个表示隐式引用捕捉这样我们lambda表达式中用了哪些变量编译器就会自动捕捉哪些变量。4.第三种捕捉方式是在捕捉列表种混合使用隐式捕捉和显示捕捉。[,x]表示其他变量隐式值捕捉x引用捕捉[xy]表示其他变量隐式引用捕捉x和y值捕捉。当使用混合捕捉时第一个元素必须是或并且混合捕捉时后面的捕捉变量必须是值捕捉同理混合捕捉时后面的捕捉变量必须是引用捕捉。5.lambda表达式如果在函数局部域中他可以捕捉lambda位置之前定义的变量不能捕捉静态局部变量和全局变量静态局部变量和全局变量也不需要捕捉lambda表达式中可以直接使用。这也意味着lambda表达式如果定义在全局位置捕捉列表必须为空。6.默认情况下lambda捕捉列表是被const修饰的也就是说传值捕捉的过来的对象不能修改mutable加在参数列表的后面可以取消其常量性也就是说使用该修饰符后传值捕捉的对象就可以修改了但是修改的是形参对象不会影响实参。使用该修饰符后参数列表不可省略即使参数为空int x 0; auto func1 []()//捕捉列表必须为空因为全局变量不用捕捉就可以用没有可捕捉的变量 { x; }; int main() { //只能用当前lambda局部域捕捉的对象全局对象 int a 0, b 1, c 2, d 3; auto func1 [a, b] { //值捕捉的变量不能修改引用捕捉可以修改 b; int ret a b; return ret; }; cout func1() endl; //隐式值捕捉 //用了哪些变量就捕捉哪些变量不能修改 auto func2 [] { int ret a b c; return ret; }; cout func2() endl; //隐式引用捕捉 //用了哪些变量就捕捉哪些变量能修改 auto func3 [] { a; b; c; }; func3(); cout a b c d endl; //混合捕捉 auto func4 [, a, b] { //a、b值捕捉不能修改 //a; //b; c; d; return a b c d; }; func4(); cout a b c d endl; auto func5 [, a, b] { //除了a、b值都不能修改 a; b; /*c; d;*/ return a b c d; }; func4(); cout a b c d endl; //局部的静态和全局变量不能捕捉也不需要捕捉 static int m 0; auto func6 [] { int ret x m; return ret; }; cout func6() endl; //mutable相当于去掉const属性就可以修改了 //但是修改了不会影响外面被捕捉的值因为是一种拷贝 auto func7 []()mutable { a; b; c; d; return a b c d; }; cout func7() endl; cout a b c d endl; return 0; }三、lambda的应用在学习lambda表达式之前我们的使用的可调用对象只有函数指针和仿函数对象函数指针的类型定义起来比较麻烦仿函数要定义一个类相对会比较麻烦。使用lambda去定义可调用对象既简单又方便。//lambda的使用 struct Goods { string _name; double _price; int _evaluate; //... Goods(const char* str, double price, int evaluate) :_name(str) ,_price(price) ,_evaluate(evaluate) {} }; //仿函数 struct ComparePriceLess { bool operator()(const Goods gl, const Goods gr) { return gl._price gr._price; } }; struct ComparePriceGreater { bool operator()(const Goods gl, const Goods gr) { return gl._price gr._price; } }; int main() { vectorGoods v { {苹果,5.5,1},{香蕉,1.8,2}, {梨,2.3,2} }; //类似这样的场景我们实现仿函数对象或者函数指针支持商品中不同项的比较。相对还是比较麻烦的这里用lambda解决就很方便 sort(v.begin(), v.end(), ComparePriceGreater()); sort(v.begin(), v.end(), ComparePriceLess()); //lambda sort(v.begin(), v.end(), [](const Goods g1, const Goods g2) { return g1._price g2._price; }); sort(v.begin(), v.end(), [](const Goods g1, const Goods g2) { return g1._evaluate g2._evaluate; }); sort(v.begin(), v.end(), [](const Goods g1, const Goods g2) { return g1._evaluate g2._evaluate; }); return 0; }四、lambda的原理lambda的原理和范围for很像编译后从汇编指令层来看压根就没有lambda和范围for这样的东西。范围for底层是迭代器而lambda底层是仿函数对象也就是说我们写了一个lambda以后编译器会生成一个对应的仿函数的类。仿函数的类名是编译按一定规则生成的保证不同的lambda生成的类名不同lambda参数/返回类型/函数体就是仿函数operator的参数/返回类型/函数体lambda的捕捉列表本质是生成仿函数类的成员变量也就是说捕捉列表的变量都是lambda类构造参数的实参当然隐式捕捉编译器要看使用哪些就传哪些对象。class Rate { public: Rate(double rate) :_rate(rate) {} double operator()(double money, int year) { return money * _rate * year; } private: double _rate; }; int main() { double rate 0.49; //lambda auto r2 [rate](double money, int year) { return money * rate * year; }; //函数对象 Rate r1(rate); r1(10000, 3); coutr2(10000, 3)endl; return 0; }
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2421954.html
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!