我是靠谱客的博主 沉默航空,最近开发中收集的这篇文章主要介绍c++11中的lambda表达式,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

写在前面

在c++11多线程中,第一次接触到lambda表达式。利用Lambda表达式,可以方便的定义和创建匿名函数

解析

lambda完整的表达形式为:

[ capture ] ( parameters ) mutable -> return-type { statement }

[capture]表示捕获列表,捕获列表一定要出现在lambda表达式开始处,编译器根据[]判断后面是否为lambda函数,捕获列表可以捕获上下文的变量以供lambda函数使用

(parameters)参数列表,与普通函数的参数列表一致,如果不需要参数传递,则可以连括号一同省略

mutable:mutable修饰,默认情况下,lambda是一个const函数,mutable可以消除其常量性,在使用该修饰符时,参数列表不可省略

->return-type:返回类型,用跟踪返回类型形式声明函数的返回类型,出于方便,需要返回值的时候可以连同符号->一起省略,此外,在返回类型明确的情况下,也可省略该部分,让编译器对返回类型进行推导。

{statement}:函数体,内容与普通函数一样,不过除了使用参数之外,还可以使用所有捕获的变量。

int main()   //各种类型的lambda函数
{
	[] {};
	int a = 3, b = 4;
	[=] {return a + b; };
	auto fun1 = [&](int c) {b = a + c; };
	auto fun2 = [=, &b](int c)->int {return b += a + c; };

	return 0;
}

lambda表达式和函数最大的不同是:lambda可以通过捕捉列表访问上下文中的数据

捕捉列表可以有多个项组成,其中由逗号隔开,捕捉列表的形式:

[var]表示值传递方式捕捉变量var
[=]表示值传递方式捕捉所有父作用域的变量(包括this指针)
[&var]表示引用传递捕捉变量var
[&]表示引用传递捕捉所有父作用域的变量(包括this指针)
[this]表示值传递方式捕捉当前的this指针
[=,&a,&b]表示以引用传递的方式捕捉变量 a 和 b,而以值传递方式捕捉其他所有的变量
[&,a,this]表示以值传递的方式捕捉 a 和 this,而以引用传递方式捕捉其他所有变量

但是捕捉列表中不允许变量的重复传递,如:

[=, a]= 已经以值传递方式捕捉了所有的变量,捕捉a重复
[&,&this] & 已经以引用传递方式捕捉了所有变量,捕捉 this 重复

栗子

#include <iostream>
#include <string>
#include <thread>
#include <list>
#include <mutex>
using namespace std;

int main()
{
	int a = 3, b = 4;
	auto Add_1 = [&]()->int {return a + b; };
	auto Add_2 = [=] {return a + b; };
	
	cout << Add_1() << endl;  //7
	cout << Add_2() << endl;  //7
	return 0;
}

lambda与仿函数

之前在STL中提到过仿函数,我们知道,相对于函数,仿函数具有初始化状态,一般是通过class定义的私有成员,并在对象声明时,对他进行初始化,私有成员函数就变成了仿函数的初始状态,因此一个仿函数对象可以有多个不同初始状态的实例

#include <iostream>
#include <string>
#include <thread>
#include <list>
#include <mutex>
using namespace std;
class rate
{
private:
	float _rate;
public:
	rate(float a): _rate(a) {}
	float operator()(float price)
	{
		return price * (1 - _rate / 100);
	}
};

int main()
{
	float tax_rate = 5.5f;
	rate changi(tax_rate);

	auto changi2 = [tax_rate](float price)->float {return price * (1 - tax_rate / 100); };

	float purchased = changi(3369);
	float purchased2 = changi2(2899);

	return 0;
}

由此栗子可以看出,lambda捕捉了tax_rate变量,仿函数使用tax_rate进行初始化,可以看出,两者除了在语法上有不同之外,lambda和仿函数有着相同的内涵,都可以捕捉一些变量作为初始状态,并接受参数进行运算。

事实上,仿函数使编译器实现lambda的一种方式

值传递和引用传递的区别

#include <iostream>
#include <string>
#include <thread>
#include <list>
#include <mutex>
using namespace std;

int main()
{
	int j = 12;
	auto by_val_lambda = [=] {return j + 1; };
	auto by_ref_lambda = [&] {return j + 1; };

	cout << by_val_lambda() << endl;
	cout << by_ref_lambda() << endl;
	
	j++;
	cout << by_val_lambda() << endl;
	cout << by_ref_lambda() << endl;
	return 0;
}

在lambda中值传递和引用传递,第二次调用by_val_lambda函数时,计算的是12+1,在第二次调用by_ref_lambda函数时,计算的是13+1,原因在于:by_val_lambda中,j作为一个常量,在初始化后就不会发生变化,而by_ref_lambda中,j仍然为负父作用域中的值

lambda的类型

在c++11中的定义上可知,lambda类型被定义为“闭包”的类,每个lambda表达式会产生一个闭包类型的临时变量(右值),因此,严格地讲,lambda函数并非函数指针。不过c++11允许lambda表达式向函数指针的转换,但是前提是lambda函数没有捕获任何变量,且函数指针所示的函数原型,必须跟lambda函数有着相同的调用方式

#include <iostream>
using namespace std;

int main()
{
	int girs = 3, boys = 4;
	auto totalChild = [](int x, int y)->int { return x + y; };
	typedef int(*allChild)(int x, int y);                        //自定义数据类型allChild,一个指向函数的指针,指向一个返回型为int,参数为两个int的函数
	typedef int(*oneChild)(int x);

	allChild p;                       
	p = totalChild;       //可以转换

	oneChild q;
	//q = totalChild;     //编译失败!参数必须一致

	decltype(totalChild) allPeople = totalChild; // 需通过decltype获得lambda的类型
	//decltype(totalChild) totalPeople = p;		 // 编译失败,指针无法转换lambda

	return 0;
}

 

参考书籍

《深入理解c++11,c++11新特性理解与应用》

 

 

最后

以上就是沉默航空为你收集整理的c++11中的lambda表达式的全部内容,希望文章能够帮你解决c++11中的lambda表达式所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(65)

评论列表共有 0 条评论

立即
投稿
返回
顶部