C++11 lambda函数

lambda表达式介绍

lambda表达式: C++11引入的一项新技术,表示一个可调用的代码单元。可理解为一个未命名的内联函数,表示形式:

 [capture](parameters) mutable -> return type { fuction body};
#include <iostream>
int main()
{
    int iX = 3, iY = 4;
    auto f = [](int x, int y)->int{return x+y;}
	std::cout<<"f: " << f(iX,iY) << std::endl;
	return 0;
}
  • lambda函数和普通函数相比,不需要定义函数名,用[]说明是lambda函数;采样追踪返回类型的方式声明其返回值。其他方面和普通函数一样;
  • 直观的讲,lambda函数和普通函数最大的区别之一是:lambda函数可以通过捕获列表访问一些上下文中的数据(即捕获列表指定了上下文中的哪些数据可以被lambda使用);
  • lambda函数等同于一个“局部函数(即在函数作用域中定义的函数)”。局部函数通常仅属于其父作用域,能访问父作用域的变量,且在其父作用域中使用。C/C++语言标准不允许局部函数的存在,但C++11标准使用lambda函数打破了这个规则;

捕获列表

捕获列表[capture]: []是lambda表达式开始的标志,是指定lambda可以使用局部变量的地方,由如下形式:

表示说明
[ ]默认不捕获任何变量,但函数体内可以使用静态变量和全局变量
[name]值捕获,可以有多个,逗号分割(只捕获捕获列表中的参数,这些参数在lambda所在的函数中是已存在的),如 [iCount,szName]
[&name]引用捕获,可以有多个,逗号分割(只捕获捕获列表中的参数),lambda函数中对捕获的参数改变,外面的参数值也随之改变
[=]lambda所在的函数中所有已存在的变量都被依照传值的方式捕获
[&]lambda所在的函数中所有已存在的变量都被依照传引用的方式捕获
[=,&name]值捕获lambda所在的函数中所有已存在的变量,除了引用捕获的变量,引用捕获的变量按照引用捕获处理
[&,name]引用捕获lambda所在的函数中所有已存在的变量,除了值捕获的变量,值捕获的变量按照值捕获处理
[this]值捕获,捕捉当前的this指针,让lambda表达式有和当前类成员函数同样的访问权限

全局变量和静态变量

#include <iostream>
int iParam = 10;    //全局变量
int main()
{
    //static int iParam = 10;  //静态
	auto f = [] {iParam = 20; };       //空捕获
	f(); //调用
	std::cout << "iParam: " << iParam << std::endl;  //iParam: 20
	auto f1 = [=]() {iParam = 40; };
	f1();
	std::cout << "iParam: " << iParam << std::endl;  //iParam: 40
	auto f2 = [&]() {iParam = 50; };
	f2();
	std::cout << "iParam: " << iParam << std::endl;  //iParam: 50
	return 0;
}

值传递

#include <iostream>
int main()
{
	int iParam = 10;
	auto f = [iParam]() {int iVar = iParam + 2; return iVar; };
	//传入的是值,函数体内直接对iParam的复制体操作,对iParam 没影响,f()使用的iParam是此函数上面最新的iParam的值
	//后面f()使用的iParam 一直是10,因为每次调用f()都是传的是iParam = 10的复制体
	std::cout << "iParam: " << iParam << ", f: " << f() << std::endl;  //iParam: 10, f: 12
	iParam = 20;
	std::cout << "iParam: " << iParam << ", f: " << f() << std::endl;  //iParam: 20, f: 12

	//

	int iParam1 = 10, iParam2 = 10;
	//auto f = [iParam1] {iParam1 = 1; };   //不能编译,值传递,iParam1是不能更新的左值,相当于只读,只能使用不能更改

	//[name1,name2] 显示捕获,指定要捕获的多个局部变量,用逗号隔开
	auto f1 = [iParam1, iParam2] {return iParam1 + iParam2; };
	std::cout << "f1: " << f1() << std::endl;  //f1: 20

	//[=]隐形值捕获,捕获lambda所在的函数中所有已存在的变量
	auto f2 = [=] {return iParam1 + iParam2; }; //捕获main()函数中lambda表达式上面的所有局部变量
	std::cout << "f2: " << f2() << std::endl;  //f2: 20
	return 0;
}

引用传递

#include <iostream>
int main()
{
	int iParam = 10;
	auto f = [&iParam]() {int iVar = iParam + 2; return iVar; };
	//传入的是引用,函数体内直接对iParam操作,f()使用的iParam是最新的iParam的值
	//后面f()使用的iParam 一直最新的iParam的值,因为每次调用f()都是传的是iParam的最新值
	std::cout << "iParam: " << iParam << ", f: " << f() << std::endl;   //iParam: 10, f: 12
	iParam = 20;
	std::cout << "iParam: " << iParam << ", f: " << f() << std::endl;   //iParam: 20, f: 22

	//

	int iParam1 = 10, iParam2 = 10;
	//[&name1,&name2] 显示捕获
	auto f1 = [&iParam1, &iParam2] {iParam1 = 30, iParam2 = 30; };
	f1();
	std::cout << "iParam1: " << iParam1 << ", iParam2: " << iParam2 << std::endl;   //iParam1: 30, iParam2: 30

	//[&]隐形捕获,捕获lambda所在的函数中所有已存在的变量
	auto f2 = [&] {iParam1 = 40, iParam2 = 40; }; 
	//捕获main()函数中lambda表达式上面的所有局部变量
	f2();
	std::cout << "iParam1: " << iParam1 << ", iParam2: " << iParam2 << std::endl;  //iParam1: 40, iParam2: 40

	return 0;
}

部分引用传递,部分值传递

#include <iostream>
int main()
{
	int iParam1 = 10, iParam2 = 10;
	//[&,name] 引用捕获lambda所在的函数中所有已存在的变量,除了值捕获的变量,值捕获的变量按照值捕获处理
	auto f = [&, iParam1] {iParam2 = 20; return iParam1; };
	f();
	std::cout << "iParam1: " << iParam1 << ", iParam2: " << iParam2 << std::endl;   //iParam1: 10, iParam2: 20


	int iParam3 = 10, iParam4 = 10;
	//[=,&name] 值捕获lambda所在的函数中所有已存在的变量,除了引用捕获的变量,引用捕获的变量按照值引用捕获处理
	auto f1 = [=, &iParam3] {iParam3 = 20; return iParam4; };
	f1();
	std::cout << "iParam3: " << iParam3 << ", iParam4: " << iParam4 << std::endl;   //iParam3: 20, iParam4: 10
	return 0;
}

参数列表

  • 参数列表(parameters):和普通函数参数列表一致。
    若不需要输入参数可省略括号"()";
    不支持可变参数、不能有默认参数(实参和形参个数永远相等);
#include <iostream>
#include <string>
int main()
{
	auto f = [](int iParam, const std::string& szParam)
	{
		std::cout << "iParam: " << iParam << ", szParam: " << szParam << std::endl;//  iParam: 10, szParam: UT
		return ++iParam;
	};
	std::cout << "f: " << f(10, "UT") << std::endl;   //  f: 11
	return 0;
}
#include <algorithm>
#include <iostream>
#include <vector>
int main()
{
	std::vector<int> vec{ 1, -4, 2, -3, 5 };
	//把容器中值进行排序
	std::sort(vec.begin(), vec.end(), [](int a, int b) {return a<b; });  
    //遍历容器中值
	for_each(vec.begin(), vec.end(), [](int a) {std::cout<<"a: "<<a<<std::endl; });  
	return 0;
}

修饰符

  • 修饰符mutable: 默认情况下,lambda函数总是一个const类型函数。mutable修饰符可取消其常量性质的。若使用mutable修饰符,参数列表不可省略(即使参数为空);
  • 一般使用默认的即可,很少用到要取消其常量性质;
auto f = []mutable {return 10; };    //无法编译
auto f1 = []()mutable {return 10; };   //正常使用
#include <iostream>
int main()
{
	int iParam = 10;
	//auto f = [iParam]{iParam += 10; };   //无法编译
	auto f = [iParam]()mutable {iParam += 10; std::cout << "iParam: " << iParam << std::endl; };
	f();        //iParam = 10+10 = 20
	std::cout << "iParam: " << iParam << std::endl;  //iParam: 10
	f();         //iParam = 10+ 10 +10 = 30
	std::cout << "iParam: " << iParam << std::endl;  //iParam: 10
}

值传入的参数,是不会被lambda表达式改变的,但在lambda表达式内部,传入的值就像是全局变量。

函数的返回值类型

  • 返回值类型->return type: 追踪返回类型形式声明函数的返回类型。
    若不需要返回值,可省略;
    类型明确时也可省略,编译器会推断返回类型;
    编译器不能推断出其返回类型时需要显示指定返回类型;
auto f = []() mutable ->int {return 10; };  //正确
auto f = []() ->int {return 10; };//正确
auto f = []{return 10; };//正确
#include <algorithm>
#include <iostream>
#include <vector>
int main()
{
	std::vector<int> vec{ 1, -4, 2, -3, 5 };
	//把容器中的负值变为正值
	std::transform(vec.begin(), vec.end(), vec.begin(), [](int i) {return i < 0 ? -i : i; });   //VS2010和VS2019都可编译
	std::transform(vec.begin(), vec.end(), vec.begin(), [](int i) {if (i < 0) return -i; else return i; }); 
	 //VS2010编译失败(无法推测返回值),VS2019可以编译(可推测返回值)
	std::transform(vec.begin(), vec.end(), vec.begin(), [](int i) ->int {if (i < 0) return -i; else return i; });//VS2010和VS2019都可编译
	return 0;
}

函数体

  • 函数体{ fuction body}: 和普通函数的函数体一样,不过除了可以使用参数之外,还可以使用所有捕获的变量。

lambda表达式C++14开始允许形参使用auto

VS2019默认使用C++14

#include <algorithm>
#include <iostream>
#include <vector>
int main()
{
	std::vector<int> vec{ 1, -4, 2, -3, 5 };
	//把容器中值进行排序
	std::sort(vec.begin(), vec.end(), [](auto a, auto b) {return a < b; });
	//遍历容器中值
	for_each(vec.begin(), vec.end(), [](auto a) {std::cout << "a: " << a << std::endl; });
	return 0;
}

VS2010编译以上程序会失败,VS2019可以使用

仿函数实现排序算法调用

#include "Test.h"
#include <vector>
#include <functional>
#include <algorithm>

void ValueSort(std::function<bool(int,int)> func, std::vector<int>& vec)
{
	std::sort(vec.begin(), vec.end(), func);
	return;
}
bool GreaterThan(int iA, int iB) { return iA >= iB; };
bool LessThan(int iA, int iB) { return iA <= iB; }; 
int main() 
{
	std::vector<int> vec{ 1, -4, 2, -3, 5 };
	ValueSort(GreaterThan, vec);
	for_each(vec.begin(), vec.end(), [](auto a) {std::cout << a << ", " ; });     //5, 2, 1, -3, -4,
	std::cout << "" << std::endl;
	ValueSort(LessThan, vec);
	for_each(vec.begin(), vec.end(), [](auto a) {std::cout << a << ", "; });        //-4, -3, 1, 2, 5,
}

模板函数实现排序算法调用

C++11中Lambda的使用

#include "Test.h"
#include <vector>
#include <functional>
#include <algorithm>

template<class Func>
void ValueSort(Func func, std::vector<int>& vec)
{
	std::sort(vec.begin(), vec.end(), func);
	return;
}
int main()
{
	std::vector<int> vec{ 1, -4, 2, -3, 5 };
	ValueSort([](int iA, int iB) { return iA <= iB; }, vec);
	for_each(vec.begin(), vec.end(), [](auto a) {std::cout << a << ", "; });        //-4, -3, 1, 2, 5,
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

qzy0621

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值