c++--lambda表达式及仿函数
目录
lambda表达式
格式

lambda表达式相当于一个匿名函数或者可调用的匿名对象,如果不把它储存在包装器等容器,那么调用一次后就销毁。
简单使用
int main()
{
//在创建lambda表达式时调用它,传入参数5和6,调用后lambda表达式销毁
[](int x, int y)->void {cout << x + y << endl; }(5, 6);
}
结果是:

int main()
{
//将lambda储存起来,lambda的生命周期和add相同,可以多次调用
//auto自动推导类型,此处是包装器function
auto add = [](int x, int y)->void {cout << x + y << endl; };
add(1,6);
add(3,6);
}
结果是:

捕捉列表
介绍
[capture-list] : 捕捉列表,该列表总是出现在lambda函数的开始位置,编译器根据[]来判断接下来的代码是否为lambda函数(因此就算不捕捉变量,[]也不能省略),捕捉列表能够捕捉上下文中的变量供lambda 函数使用。
注意
lambda函数默认只能使用lambda函数体内部的变量以及全局变量,比如

想要使用局部变量,需要对其进行捕捉
捕捉方式
传值捕捉
int var = 10;
int main()
{
int data1 = 5;
int data2 = 6;
[data1,data2](int x,int y)->void
{
cout << x<< " ";
cout << y << " ";
cout << var << " ";
cout << data1 << " ";
cout << data2 << " ";
}(1,2);
}//报错!!
程序报错!
传值捕捉本质上是一种拷贝,不影响外面的变量。捕捉到的变量无法修改只能使用,除非lambda表达式被mutable修饰符修饰(修改了也不影响外面的变量)。
传引用捕捉:
int var = 10;
int main()
{
int data1 = 5;
int data2 = 6;
[&data1,&data2](int x,int y)->void
{
cout << x<< " ";
cout << y << " ";
cout << var << " ";
cout << data1 << " ";
cout << data2 << " ";
data1 = 999;
}(1,2);
cout << data1 << endl;
}

本质是引用,会影响外面的变量。无论是否加mutable都可以修改。
‘=’ —— 以值捕捉捕捉所有可捕捉的变量
int var = 10;
int main()
{
int data1 = 5;
int data2 = 6;
[=](int x,int y)->void
{
cout << x<< " ";
cout << y << " ";
cout << var << " ";
cout << data1 << " ";
cout << data2 << " ";
}(1,2);
}
‘&’ —— 以引用捕捉捕捉所有可捕捉的变量
int var = 10;
int main()
{
int data1 = 5;
int data2 = 6;
[&](int x,int y)->void
{
cout << x<< " ";
cout << y << " ";
cout << var << " ";
cout << data1 << " ";
cout << data2 << " ";
data1 = 999;
data2 = 999;
}(1,2);
cout << data1 << ":" << data2 << endl;
}

传值捕捉除了data2的所有变量,只有data2是传引用捕捉
int var = 10;
int main()
{
int data1 = 5;
int data2 = 6;
[=,&data2](int x,int y)->void
{
cout << x<< " ";
cout << y << " ";
cout << var << " ";
cout << data1 << " ";
cout << data2 << " ";
data1 = 999;//报错
data2 = 999;
}(1,2);
cout << data1 << ":" << data2 << endl;
}
不可以重复捕捉:


其他部分
(parameters):参数列表。
与普通函数的参数列表一致,如果不需要参数传递,则可以 连同()一起省略
mutable:修饰符。
默认情况下,lambda函数值捕捉获得的变量不能修改(即使它是副本,不会影响外界变量),加了mutable修饰符就可以在lambda函数体中修改它。本质上,mutable把仿函数类中的运算符重载的const属性去掉了,使得成员变量变得可以修改(见后记)。
使用该修饰符时,参数列表不可省略(即使参数为空)。
-> returntype:返回值类型。
没有返回值时此部分可省略。返回值类型明确情况下,也可省略,由编译器对返回类型进行推导。
{statement}:函数体。
在该函数体内,除了可以使用其参数外,还可以使用所有捕获到的变量。
注意:
在lambda函数定义中,参数列表和返回值类型都是可选部分,而捕捉列表和函数体可以为空,但不能省略。因此C++11中最简单的lambda函数为:[]{}; 该lambda函数不能做任何事情
事实上,lambda的底层与仿函数,即函数对象很相似,lambda捕捉到的变量就是以成员变量的方式存储的,捕捉的本质是用构造函数初始化。
仿函数
仿函数就是重载()运算符的类的对象,使对象可以像函数一样调用
举个例子:
class Compare
{
public:
bool operator()(int x,int y)
{
return x > y;
}
};
int main()
{
Compare compare;
cout<<compare(1,2)<<endl;//像函数一样调用它
}
后记-理解
编译器遇到lambda表达式本质上会做几件事:
创建一个仿函数类,该类重载了()运算符,()运算符重载内部就是lambda表达式的函数体。
把捕捉到的变量在仿函数类中用成员变量表示。
创建一个仿函数类的临时对象并()调用。
// 你写的Lambda
int x = 10;
auto mylambda = [x]() { return x + 1; };
// 编译器大致生成的代码
class __AnonymousLambda {
private:
int x; // 捕获的变量成为成员变量
public:
__AnonymousLambda(int _x) : x(_x) {} // 构造函数初始化捕获的变量
int operator()() const { return x + 1; } // 函数调用运算符
};
__AnonymousLambda mylambda(x); // 实际上mylambda就是__AnonymousLambda构造出来的对象
补充
mutable除了上述在lambda中的作用,还有一个作用就是用于修饰类内的非静态成员变量,表示即使被const修饰的成员函数也可以修改指定的成员变量。
更多推荐



所有评论(0)