Lambda表达式总结

一、Lambda 的语法形式

Lambda 的语法形式如下:
[外部变量访问方式说明符] (参数表) mutable 或 exception 声明 -> 返回值类型 {函数体}
Lambda表达式具体实例形式如下 : [capture] (parameters)->return_type{ body }
[=](int x, int y) -> bool { return x % 10 < y % 10; }
可以看到,Lambda 主要分为五个部分:[外部变量访问方式说明符]、(参数表)、mutable 或 exception 声明、-> 返回值类型、{函数体}.

二、Lambda使用说明

1、 外部变量访问方式说明符用于捕获外部变量,使得匿名函数体可以使用这些变量,捕获的方法分为引用捕获和值(拷贝)捕获两种
    [] 不捕获任何变量;
    [&] 按引用捕获所有外部变量;
    [=] 按值捕获所有外部变量
    [&, var] 默认按引用捕获,仅按值捕获 var;
    [=, &var] 默认按值捕获,仅按引用捕获 var;

显示捕获  

      Lambda表达式通过在最前面的方括号[]来明确指明其内部可以访问的外部变量,这一过程也称作Lambda表达式“的显示捕获

隐式捕获

    除了显式列出我们希望使用的来自所在函数的变量之外,还可以让编译器根据lambda体中的代码来推断我们要使用哪些变量。
2、 mutable 或 exception 声明
    这部分可以省略。按值传递函数对象参数时,加上 mutable 修饰符后,可以修改传递进来的拷贝(注意是能修改拷贝,而不是
    值本身)。exception 声明用于指定函数抛出的异常,如抛出整数类型的异常,可以使用 throw(int)。  
3、 利用->标识函数返回值的类型,当返回值为 void,或者函数体中只有一处 return 的地方(此时编译器可以自动推断出返回值类型) 时,这部分可以省略。

三、代码演示

#include <iostream>
#include <string>
#include <algorithm>
#include <functional>
#include <vector>
#include <exception>
#include <assert.h>

//函数外值传递与引用传递
void capture_example();
//mutable实例
void mutable_example();
//排序实例
void sort_example();
//数组综合实例
void vector_example();
//回调实例
void Callback_example();

int menu() {
	int choice;

	std::cout << " **** Menu **** " << std::endl << std::endl;
	std::cout << "(1) capture_example. " << std::endl;
	std::cout << "(2) mutable_example. " << std::endl;
	std::cout << "(3) sort_example. " << std::endl;
	std::cout << "(4) vector_example. " << std::endl;
	std::cout << "(5) Callback_example. " << std::endl;
	std::cout << "(6) Quit. " << std::endl << std::endl;
	std::cout << "Your choice: ";
	std::cin >> choice;
	std::cout <<  std::endl;

	return choice;

}
int main()
{
	bool exit = false;
	while (1)
	{
		system("cls");  //清屏
		int choice = menu();
		switch (choice) {
		case (1):
			capture_example();
			system("pause");
			break;
		case (2):
			mutable_example();
			system("pause");
			break;
		case (3):
			sort_example();
			system("pause");
			break;
		case (4):
			vector_example();
			system("pause");
			break;
		case (5):
			Callback_example();
			system("pause");
			break;
		case (6):
			exit = true;
			break;
		default:
			std::cout << "Please select again! " << std::endl;
			break;
		}

		if (exit == true)
			break;
	} 

}

void capture_example()
{
	int i=2;
	int j = 4;
	int k = 6;
	//AnonyFunc函数声明定义
	auto by_val_lambda = [=,&j,&k]() -> void
	{
		std::cout <<"by_val_lambda  :"<<i << std::endl;//2
		std::cout <<"by_val_lambda  :"<< &i << std::endl;
		std::cout << "by_val_lambda  :" << j << std::endl;//0
		std::cout << "by_val_lambda  :" << k << std::endl;//9
			
	};
	auto by_ref_lambda = [&,j,k]() -> void
	{
		std::cout << "by_ref_lambda  :" << i << std::endl;//2
		std::cout << "by_ref_lambda  :" << &i << std::endl;
		std::cout << "by_ref_lambda  :" << j << std::endl;//4
		std::cout << "by_ref_lambda  :" << k<< std::endl;//6

	};
	i = 1;
	j = 0;
	k = 9;
	std::cout << "current value  :" << i << std::endl;//1
	std::cout << "current address:" << &i << std::endl;
	std::cout << "current value  :" << j << std::endl;//0
	std::cout << "current value  :" << k << std::endl;//9
	//AnonyFunc函数调用
	by_val_lambda();
	by_ref_lambda();
}
void mutable_example()
{
	int val = 0;
	// 对于const的成员函数,修改非静态的成员变量,所以就出错了
	// auto const_val_lambda = [=](){ val = 3; }; //wrong!!!
	// 对与mutable标识的lambda表达式,以值传递方式捕获的变量可以在表达式内部修改,但作用域仅限于表达式内部,外部变量的值不会被改变
	auto mutable_val_lambda = [=]() mutable {val = 3; std::cout << val << std::endl;/*3*/ };
	mutable_val_lambda();
	std::cout << val << std::endl; // 0
	auto const_ref_lambda = [&]() { val = 4; };
	const_ref_lambda();;
	std::cout << val << std::endl; // 4
	auto mutable_ref_lambda = [&]() mutable { val = 5; };
	mutable_ref_lambda();
	std::cout << val << std::endl; // 5
	int a1 = 111, b = 222;
	auto func = [=, &b]() mutable { a1 = 22; b = 333; std::cout << "a:" << a1 << " b:" << b << std::endl;/*a:22  b:333*/ };
	func();
	std::cout << "a1:" << a1 << " b:" << b << std::endl;//a:111  b:333
	try
	{
		int x = 3;
		int y = 2;
		auto func_division = [x, y]() mutable /*throw()*/
		{
			y = 0;
			if (y == 0) throw (y);
			return x / y;
		};
		func_division();
	}
	catch (int)
	{
		std::cout << "error of Integer division by zero " << std::endl;
		//exit(1); //异常退出程序
	}

}
void sort_example()
{
	int a[4] = { 11, 4, 2, 33 };
	std::sort(a, a + 4, [=](int x, int y) -> bool { return x % 10 < y % 10; });
	std::for_each(a, a + 4, [=](int x) { std::cout << x << " "; });//11 2 33 4
	std::cout << std::endl;
}
double eval(std::function<double(double)> f, double x = 2.0) { return f(x); }
void vector_example()
{
	//auto  eval = [](std::function<double(double)> f, double x = 2.0) { return f(x); };
	auto newline= []() {std::cout << std::endl;  };
	std::function<double(double)> f0 = [](double x) {return 1; };
	auto                          f1 = [](double x) {return x; };
	decltype(f0)                  fa[3] = { f0,f1,[](double x) {return x * x; } };
	std::vector<decltype(f0)>     fv = { f0,f1 };
	fv.push_back([](double x) {return x * x; });
	for (size_t i = 0; i < fv.size(); i++)  { std::cout << fv[i](2.0) << "\t" ;}//1   2   4
	newline();
	for (size_t i = 0; i < 3; i++)          { std::cout << fa[i](2.0) << "\t"; }//1   2   4
	newline();
	for (auto& f : fv)                   { std::cout << f(2.0) << "\t"; }//1   2   4
	newline();
	for (auto& f : fa)                   { std::cout << f(2.0) << "\t"; }//1   2   4
	newline();
	std::cout << eval(f0) << "\n";//1
	std::cout << eval(f1) << "\n";//2
	//一个没有指定任何捕获的lambda函数,可以显式转换成一个具有相同声明形式函数指针
	
	//std::cout << [](std::function<double(double)> f, double x = 2.0) { return f(x); }(f0) << "\n";
	//std::cout << [](std::function<double(double)> f, double x = 2.0) { return f(x); }(f1) << "\n";
	auto a_lambda_func = [](int x) {std::cout << "calls the lambda" << std::endl; };
	void(*func_ptr)(int) = a_lambda_func;
	func_ptr(4); //calls the lambda
}
template <class Callback>
int CollectFeatures(Callback CB)
{
	int count = 0;
	for (int i = 0; i < 10; i++)
	{
		if (CB(i))
		{
			count++;
		}
	}
	return count;
}
bool AddFeature(size_t Feature)
{
	return Feature % 2;
}
void Callback_example()
{
	int i = CollectFeatures([](size_t Feature) -> bool { return AddFeature(Feature); });
	std::cout << i << std::endl;//5
}

四、注意点

1、 在lambda匿名函数体里边,按值捕获到的变量,实质上是调用者函数中变量的只读拷贝(read - only),后面变量值更改,不改变捕获的变量值,按引用捕获,调用者函数中该变量的值,随调用时引用值的变化而变化。

2、 按值捕获到的变量,加入了mutable后,匿名函数体内部可以修改这个拷贝的值,也就是说调用者函数中该变量的值依然不会被改变;

3、 捕获列表为空,完全相当于调用普通函数。可以显式转换成一个具有相同声明形式函数指针。

4、当混合使用隐式捕获和显式捕获时,捕获列表中的第一个元素必须是一个”&”或”=“。此符号指定了默认捕获方式为引用或值;并且显式捕获的变量必须使用与隐式捕获不同的方式。即,如果隐式捕获是引用方式,则显式捕获命名变量必须采用值方式;类似的,如果隐式捕获采用的是值方式,则显式捕获命名变量必须采用引用方式。

五、总结

1、lambda 表达式,即用即删除,很适合需要完成一项功能,但是此功能只在此一处使用。

2、lambda表达式使用方便、代码简洁、定义和使用在同一个地方,而且不需要取名字就可以使用,它本身就是一个匿名的函数。

3、lambda表达式可以作为回调函数,传递给某些应用,比如消息处理。

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值