Lambda表达式简介
Lambda表达式是现代C++在C++11和更高版本中的一个新的语法糖。它是一种定义匿名函数对象的便捷方法,常用于封装传递给算法或异步方法的几行代码。Lambda表达式可以在调用或作为函数参数传递的位置处定义,可以捕获上下文中的变量供函数使用。Lambda表达式的语法定义包括捕获列表、参数列表、可变规格、异常说明、返回类型和函数体。捕获列表描述了Lambda函数可以访问的上下文变量及传递方式,参数列表类似于普通函数的参数列表,可变规格用于取消Lambda函数的常量性,异常说明用于指示Lambda函数是否会引发异常,返回类型可以省略让编译器推导,函数体可以包含任意内容。Lambda表达式的优点包括在需要调用函数的位置定义短小精悍的函数,代码紧凑且可读性高。缺点是语法相对灵活增加了阅读难度,对于函数复用有限。Lambda表达式的工作原理是编译器会把Lambda表达式生成一个匿名类的匿名对象,并在类中重载函数调用运算符,实现了一个operator()方法。这样可以用Lambda表达式构造一个函数对象。
Lambda表达式在C++中的语法定义
在C语言中,没有直接支持Lambda表达式的语法。 Lambda表达式是C++11引入的新特性,它允许在函数调用或作为函数参数传递的位置定义匿名函数对象。C++的Lambda表达式的语法定义与函数定义相似,一般形式为:
[捕获列表](参数列表) mutable noexcept -> 返回类型 {函数体}
示例 1 :
int main()
{// 两个数相加的lambdaauto add1 = [](int a, int b)->int{return a + b; };cout << add1(1, 2) << endl;// 省略返回值auto add2 = [](int a, int b){return a + b; };cout << add2(1, 2) << endl;return 0;
}
示例2
int main()
{// 交换变量的lambdaint x = 0, y = 1;auto swap1 = [](int& x1, int& x2)->void {int tmp = x1; x1 = x2; x2 = tmp; };swap1(x, y);cout << x << ":" << y << endl;auto swap2 = [](int& x1, int& x2){int tmp = x1;x1 = x2;x2 = tmp;};swap2(x, y);cout << x << ":" << y << endl;// 不传参数交换x y的lambda -- 捕捉列表// 默认捕捉的对象不能修改/*auto swap3 = [x, y]()mutable{int tmp = x;x = y;y = tmp;};swap3();cout << x << ":" << y << endl;*/auto swap4 = [&x, &y]{int tmp = x;x = y;y = tmp;};swap4();cout << x << ":" << y << endl;return 0;
}
Lambda表达式注意以下几个问题:
一: Lambda表达式的捕获列表有哪些形式?
1. []:表示不捕获任何变量。
int main()
{int a = 9;[]() {cout << a << endl; };system("pause");return 0;
}
2. [var]:表示值传递方式捕获变量var。
int main()
{int a = 9;auto lam = [a]() {cout << a << endl; };lam();return 0;
}
3. [var, &]:表示值传递方式捕获变量var,并通过引用传递方式捕获其他所有变量。
#include <iostream>
using namespace std;
int main()
{int a = 9;int b = 5;int &x = b;x = 8;auto lam = [a, &](){cout << a << " " <<x <<endl;};lam();return 0;
}
4. [=]:表示以值传递的方式捕获所有变量。
int main()
{int a = 9;string s = "hello";auto lam = [=]() {cout << a << " "<<s<<endl; };lam();return 0;
}
5. [&]:表示以引用传递的方式捕获所有变量。
int main()
{int a = 9;auto lam = [&a]() {a = 10; cout << a << endl; };lam();return 0;
}
6. [&, var]:表示以引用传递的方式捕获所有变量,并值传递方式捕获变量var。
int main()
{int a = 9;string s = "hello";auto lam = [&, a]() {s = "hhah"; cout << a << " " << s << endl; };lam();return 0;
}
7. [=, &var]:表示以值传递的方式捕获所有变量,并引用传递方式捕获变量var。
int main()
{int a = 9;string s = "hello";auto lam = [=, &a]() {a = 90; cout << a << " " << s << endl; };lam();return 0;
}
需要注意的是,捕获列表不允许变量重复传递,否则会导致编译时错误。
二:Lambda表达式的捕获范围
//捕捉列表的参数来源范围--当前栈帧 (注意全局变量)
int func()
{int a, b, c, d, e;a = b = c = d = e = 1;// 全部传值捕捉auto f1 = [=](){cout << a << b << c << d << e << endl;};f1();// 混合捕捉auto f2 = [=, &a](){a++;cout << a << b << c << d << e << endl;};f2();static int x = 0;if (a){auto f3 = [&, a](){//a++;//errorb++;c++;d++;e++;val++;x++;cout << a << b << c << d << e << endl;};f3();}return 0;
}int main()
{//error//auto f4 = [&, a](){// //a++;// b++;// c++;// d++;// e++;// f++;// cout << a << b << c << d << e << endl;//};//f4();return 0;
}
三: Lambda表达式可以接受哪些参数?
Lambda表达式可以接受不同类型的参数,具体取决于功能接口中声明的方法的参数类型。参数可以是基本类型、对象类型、函数式接口类型或泛型类型。Lambda表达式的参数列表可以为空,也可以有一个或多个参数。参数列表需要用圆括号括起来,多个参数之间用逗号分隔。当只有一个参数时,可以省略圆括号。Lambda表达式的参数可以在箭头符号(->)之前进行定义,并在表达式中使用。例如:(int a, int b) -> a + b 是接受两个整数参数并返回它们的和的Lambda表达式。总之,Lambda表达式提供了一种简洁的方式来传递行为作为参数,并且可以接受不同类型的参数。<span class="em">1</span><span class="em">2</span><span class="em">3</span>
四: Lambda表达式的返回类型是如何推导的?
Lambda表达式的返回类型是通过上下文推导得出的。根据Java语言规范,当Lambda表达式只有一条语句时,会自动推导返回类型。如果Lambda表达式有多条语句,则需要显式指定返回类型。 在Lambda表达式的语法中,返回类型通常是可以省略的,编译器会根据上下文自动推导出返回类型。 Lambda表达式的返回类型推导是通过invokedynamic指令实现的。
<span class="em">1</span><span class="em">2</span><span class="em">3</span>
Lambda表达式的底层
class Rate
{
public:Rate(double rate) : _rate(rate){}double operator()(double money, int year){return money * _rate * year;}private:double _rate;
};//lambda_uuid
//uuid--Universally Unique Identifier,即通用唯一识别码。
class lambda_xxxx
{
};
int main()
{// 函数对象double rate = 0.49;Rate r1(rate);r1(10000, 2);// 仿函数lambda_uuid// lambda -> lambda_uuidauto r2 = [=](double monty, int year)->double{return monty*rate*year; };r2(10000, 2);auto r3 = [=](double monty, int year)->double{return monty*rate*year; };r3(10000, 2);return 0;
}