【C++】C++11之lambda表达式

lambda表达式

含义
lambda表达式其实就是函数的用法,且以对象的方式匿名去用。

语法
【capture-list】(parameters)mutable->return-type{statement}

  • caputure-list : 捕捉列表。捕捉上下文中的变量供lambda函数使用
  • parameters:参数列表。 与普通函数的参数列表一致。可省略
  • mutable:默认情况下,lambda函数总是一个const函数,mutable可以取消其常性
  • ->returntype:返回值类型。用于追踪返回类型形式声明函数的返回值类型。
    1. 没有返回值可省略
    2. 有返回值,也可以省略。由编译器推导
  • {statemet}:函数体。 可以使用捕捉列表中的变量
    注意:在lambda函数定义中,参数列表和返回值类型都是可选部分,而捕捉列表和函数体可以为空。因此C++11中最简单的lambda函数为:[]{};该lambda函数不能做任何事情。

捕捉列表说明

  • 【val】:表示以值传递的方式捕捉变量var
  • 【=】:表示以传递的方式捕捉后面{ }中的所有变量
  • 【&val】: 表示引用传递捕捉var变量
  • 【&】:表示引用传递捕捉所有 { }的变量

注意

  1. 若语法上捕捉列表由多个捕捉项组成,并以逗号分隔。
    比如:

     【=,&a】:以引用传递的方式捕捉变量a,并以值传递的方式捕捉其他变量
     【&,a】:值传递的方式捕捉变量a,因引用方式捕捉其它变量
     【=,a】:已经以值传递的方式捕捉了所有的变量,捕捉a会重复
    

例1:

int main()
{
	//最简单的lambda表达式,没有任何意义
	[]{};

	int a = 3;
	int b = 4;
	auto e = [a,b] {return a + b ;};  //省略参数类型和返回值类型 ;【a,b】捕捉a,b
	cout << e() <<endl; //没有参数,所以要()
	auto f = [=] {return a + b;}; //代表捕捉外边的所有对象
	cout << f() << endl;
	system("pause");
}

结果
在这里插入图片描述
总结:其实lambda表达式可以理解为无名函数,直接被auto接收。 后面有讲怎么匿名调用

例2:

 int main()
{
	int a = 3;
	int b = 4;
	// auto func2 = [=](int c)->int{return b += a + c; };  
	//错误,不能在非可变的lambda中修改值。 【=】只是以传值的方式捕获,不能修改
	//所以我们要把它改为可变的。
	
	//方法1:加mutable 
	auto func1 = [=](int c)mutable->int{return b += a+c;};
	
	//方法2: 在捕获列表中加b的引用
	auto func2 = [=,&b](int c)->int{return b += a + c; };

	cout << func1(10) << endl;
	cout << func2(10) << endl;
   
	system("pause");
}


结果:
在这里插入图片描述
例3:交换a、b的lambda的例子:

int main()
{
	int a = 3;
	int b = 4;
	cout << "刚开始:" << endl;
	cout << "a:" << a << " " << "b:" << b << endl;
	//mutable改变捕捉到的a、b拷贝可以改变
	auto lamber_swap1 = [a, b]()mutable->void{int tmp = a; a = b; b = tmp; };
	lamber_swap1(); //不能发生交换,传值拷贝的方式捕捉a,b

	//正确的写法
	//捕捉列表[]中捕捉a,b的引用
	auto lamber_swap2 = [&a, &b](){int tmp = a; a = b; b = tmp; };
	lamber_swap2();
	cout << "a:" << a << " " << "b:" << b << endl;

	//捕捉列表中不写,但是参数列表中包含a,b的引用
	auto lamber_swap3 = [](int &a, int& b) {int tmp = a; a = b; b = tmp; };
	lamber_swap3(a,b);
	cout << "a:" << a << " " << "b:" << b << endl;

	//捕捉[&]列表
	auto lamber_swap4 = [&](){int tmp = a; a = b; b = tmp; };
	lamber_swap4();
	cout << "a:" << a << " " << "b:" << b << endl;
	system("pause");

}

结果
在这里插入图片描述

我们接下来可以通过类比函数指针、仿函数,体验lambda函数表达式的亮点和方便

函数指针、仿函数与lambda表达式 之间的类比:
  1. 函数指针
  2. 仿函数
  3. lambda 表达式

为什么说lambda表达式能类比于函数和仿函数呢?

	template<class ..., class Compare>
	void sort(first, last,  Compare comp);

以上三个都可以传到comp这里,因为这里是一个模板,既可以传函数指针,也可以传仿函数,传lambda表达式

struct Stu
{
	string _no;
	int Eng;
	int math;
};

bool SortBymath(const Stu& s1, const Stu& s2)
{
	return s1.math < s2.math;
}

struct SortBymath_
{
	bool operator()(const Stu& s1, const Stu& s2)
	{
		return s1.math < s2.math;
	}
};

int main()
{
	Stu s[] = { { "101", 98, 99 }, { "102", 64, 79 }, { "100", 99, 74 } };

	//按数学成绩排序的三种写法
	//1.函数指针 	
	//按数学成绩整体排升序
	sort(s, s + sizeof(s) / sizeof(s[0]), SortBymath);
	

	//2.仿函数排序
	//方法1:定义一个仿函数对象传对象
	SortBymath_ smath;
	sort(s, s + sizeof(s) / sizeof(s[0]), smath);
	//方法2:本身直接传递
	sort(s, s + sizeof(s) / sizeof(s[0]), SortBymath_());

	
	//3.lambda表达式
	//math降序
	auto mathLess = [](const Stu& s1, const Stu& s2)
	{
		return s1.math < s2.math;
	};
	
	//math升序
	auto mathGreater = [](const  Stu& s1, const Stu& s2)
	{
		return s1.math > s2.math;
	};
	
	sort(s,s+sizeof(s)/sizeof(s[0]),mathLess); //排降序
	sort(s,s+sizeof(s)/sizeof(s[0]),mathGreater); //排升序
	
	system("pause");
}

	注意:lambda表达式其实都不用起名字,直接用就ok了。就上面的例子
int main()
{
	//按数学成绩升序排序
	sort(s,s+sizeof(s)/sizeof(s[0]), [](const Stu& s1, const Stu& s2)
	{
		return s1.math < s2.math;
	};
	//按数学成绩降序排序
	sort(s,s+sizeof(s)/sizeof(s[0]), [](const Stu& s1, const Stu& s2)
	{
		return s1.math > s2.math;
	};
	//也可以按英语成绩,类似。
}
函数指针 ,仿函数,C++11lambda表达式三者的对比:
  1. 函数指针
    C语言沿袭而来,当做函数参数传进sort()中进行按自定义类型的排序
  2. 仿函数
    优:相比函数指针更加方便。也可以作为模板参数传参,也可以定义成对象传参。
    缺:若比较的参数过多,定义过多的模板结构体
  3. lambda表达式
    若结构体中的变量很多, 需要比较的参数变量也很多。那么我么就会写很多个函数或者仿函数,这样就很麻烦。 而lambda表达式的诞生就是为了解决这类问题。可以直接在调用函数的地方写匿名的lambda表达式。
    而且使用简便,代码简洁,可读性强。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值