C++11特性总结(2)-lambda表达式怎么用?

357 阅读3分钟

什么是lambda表达式?

一个lambda表达式表示一个可调用的代码单元,可以理解一个未命名的内联函数。它具有1个返回值,1个参数列表,1个函数体。 与普通函数不同,lambda必须用尾置返回。

格式:[captrue list] (parameter list) ->return type { funtion body};

可省略返回类型的情况:整个函数体只有return语句则将根据return语句推断返回类型。

但是如果函数体有多个return语句,没有填写返回类型的情况下,就会认为返回void。

可以省略参数列表:比如[captrue list] {funtion body} 同时省略参数列表和返回值。

使用方法

根据captrue list捕获的方式不同,可以分为四类:

  1. 值捕获
int num=2;
auto f = [num] {return num;}; //值捕获num变量

注意:捕获变量的值在lambda创建时拷贝到lambda内部(而不是lambda被调用时拷贝)

  1. 引用捕获
int num=2;
auto f = [&num] {return num;}; //引用捕获num变量

注意:引用捕获的变量,程序员要确保lambda被执行时该变量是存在的。

以上两种捕获都是显式捕获,即指明要捕获的方式和对象。

  1. 隐式捕获:只注明捕获方式,使用=表示值捕获,&表示引用捕获。至于具体的捕获对象,由编译器推断函数体使用到哪些变量
int num=2;
auto f = [=]{return num;};  //值捕获num变量
auto f2 = [&]{return num;};   //引用捕获num变量
  1. 想要特定的对象使用特定的捕获方式,一部分对象用值捕获,一部分对象用引用捕获。
[&, a]:表示a是值捕获,其余的都是引用捕获
int a = 1;
int b = 2;
auto f = [&,a]{return a+b;};//值捕获a,引用捕获b
---------------------------------------------
[=, &a]:表示a是引用捕获,其余的都是值捕获
int a = 1;
int b = 2;
auto f = [=,&a]{return a+b;};//值捕获b,引用捕获a

总结各种捕获方式:

  • []:默认不捕获任何变量
  • [=]:默认以值捕获所有变量
  • [&]:默认以引用捕获所有变量
  • [x]:仅以值捕获x,其它变量不捕获
  • [&x]:仅以引用捕获x,其它变量不捕获
  • [=, &x]:默认以值捕获所有变量,但是x是例外,通过引用捕获
  • [&, x]:默认以引用捕获所有变量,但是x是例外,通过值捕获
  • [this]:通过引用捕获当前对象(其实是复制指针)
  • [*this]:通过传值方式捕获当前对象

捕获变量修改变量值的问题

  1. 值捕获:要加上mutable关键字才可以在lambda函数体修改捕获值,否则不可修改。
int num=2;
auto f = [num] ()mutable {return ++num;};

注意:如果用mutable前面参数列表就不能完全缺省了,至少要写一个空得括号

  1. 引用捕获:能否修改取决于原变量是不是const

lambda表达式原理-函数对象

编译器为lambda表达式创建一个没有名字的函数对象,这个对象中有一个函数,是重载函数调用运算符的函数。然后将这个类传递给使用lambda表达式的函数去使用。同时这个类还可以有其他的函数 比如构造函数。值捕获就是在构造函数把这个值拷贝到类中,创建一个对应的数据成员。

auto f = [a]() -> int{ return a; };
->等价于:
class Noname
{
private:	
	int a;
public:
	Noname(int a_in):a(a_in){} //构造函数,把a拷贝到函数对象中,创建对应的数据成员
	int operator()() const
	{
		return a;
	}
};