lambda 

lambda表达式本质是一个匿名函数对象,但是他可以定义在函数内部,一般来说,我们可以直接使用auto的对象来接收lambda对象。lambda的基本表达式格式如下:

[capture-list](parameters)-> return type{function body};

其中,capture-list是捕捉列表,用于获取函数内的局部变量来给lambda函数使用。编译器是根据"[]"的存在来判断这个是否为lambda函数。所以,即使我们什么也不需要捕捉,将其为空也不可以省略。lamda的捕捉有两种方法,传值捕捉和引用捕捉。传值捕捉的参数不能在lambda函数体内修改,但是传引用捕捉的可以。传值捕捉本质上是一种const修饰的拷贝,如果想要修改,需要在函数体后面加上mutable。

int main()
{
	int x = 2;
	int y = 9;

	auto ret1 = [x,&y](int a, int b)
		{
			a += x;
			x++;//报错
			y++;
			b += y;
			return a + b; 
		};

	auto re2 = [x,&y](int a, int b)mutable
		{
			a += x;
			x++;//不报错
			y++;
			b += y;
			return a + b; 
		};
	cout << ret1(4, 5)<< endl;

	return 0;

除了传值捕捉,我们还可以使用隐式捕捉,在捕捉列表中写一个"="表示把需要的外部变量传值捕捉,写一个"&"表示把需要的外部变量传引用捕捉。当然,也可以进行特例捕捉。如下图所示。在局部函数域内,lambda只能捕捉前文定义的变量;如果lambda在全局位置,则捕捉列表为空,此时静态局部变量和全局变量lambda表达式是可以直接使用的。

auto ret1 = [=]{};//按需传值捕捉
auto ret2 = [&]{};//按需传引用捕捉
auto ret3 = [=,&y]{};//除了y引用捕捉以外,其他的按需传值捕捉
auto ret4 = [=,x]{};//除了x传值捕捉以外,其他的按需引用捕捉

lambda的应用主要是应用于代替仿函数,对于一些一些简短快速使用的函数体时,我们就可以使用lambda,例如在不同项的比较少时,简短的lambda表达式就比仿函数更加易懂。

lambda的原理底层就是仿函数,当我们写了一个lambda后,编译器会生成一个对应仿函数的类,我们在调用lambda的时候,其实调用的是这个类的operate()。

包装器

function

std::function的作用是可以将函数指针,仿函数lambda等可调用对象全部包装起来,方便声明可调用对象的类型。在包装成员函数的时候,有几点需要注意。

1:成员函数需要指定类域加上使用&符号才能获得地址

2:普通的成员函数有一个隐含的this指针,进行包装的时候需要传对象或者传指针过去

3:静态成员函数不需要传这个对象或者指针

4:推荐传对象,那么只要传一个匿名对象即可

#include<functional>

using placeholders::_1;
using placeholders::_2;
using placeholders::_3;
int f(int a, int b)
{
	return a + b;
}



struct Functor
{
public:
	int operator() (int a, int b)
	{
		return (a + b) * 2;
	}
};


class Plus
{
public:
	Plus(int n = 10)
		:_n(n){ }

	static int plus_i(int a, int b)
	{
		return (a + b) * 3;
	}

	double plus_d(double a, double b)
	{
		return (a + b) * _n;
	}


private:
	int _n;

};
int main()
{
	function<int(int, int)> f1 = f;//函数
	function<int(int, int)> f2 = Functor();//仿函数
	function<int(int, int)> f3= [](int a, int b) {return a + b;};//lambda对象

	function<int(int, int)> f4 = &Plus::plus_i;//静态成员函数

	function<double(Plus*, double, double)> f5 = &Plus::plus_d;//普通成员函数 传指针
	function<double(Plus, double , double)> f6 = &Plus::plus_d;//普通成员函数 传对象
	function<double(Plus&&, double, double)> f7 = &Plus::plus_d;//普通成员函数 传右值引用

}

bind

bind则是另一个包装器,bind可以用来调整参数个数和参数顺序。参数顺序相对没用,主要是参数个数。bind实际上是返回一个仿函数对象。_1代表第一个实参,_2代表第二个实参。参数个数的调整很有用,可以减少代码的书写,并且保证接口更加的简洁。如上面std::function中,如果我们传入的是一个普通成员函数,则每次都还要传一个函数对象或者这个对象的指针过去,很麻烦,当我们用bind直接绑定以后,就简洁了许多。

#include<functional>

using placeholders::_1;
using placeholders::_2;
using placeholders::_3;

int Sub(int a, int b)
{
	return a + b*5;
}

int main()
{

////////////////第一个功能///////////////////
	auto s1 = bind(Sub, _1, _2);
	cout << s1(1, 2) << endl;//11

	auto s2 = bind(Sub,_2, _1);
	cout << s2(1, 2) << endl;//7


///////////////第二个功能///////////////////
function<double(double, double)> f8 = bind(&Plus::plus_d,Plus(),_1,_2);
}

Logo

码道开发者社区,聚焦华为云码道 CodeArts 代码智能体,沉淀 Agent、Skill、鸿蒙开发实战内容,供开发者查阅资料、交流技术、分享工程实践

更多推荐