75 C++ lambda表达式

lambda函数是C++11标准新增的语法糖,也称为lambda表达式或匿名函数。

lambda函数的特点:距离近、简洁、高效和功能强大

实例: [](const int & i)->void {cout

语法:

 

一、参数列表

参数列表是可选的,类似普通函数的参数列表,如果没有参数列表,()可以省略不写。

与普通函数的不同:

lambda函数不能有默认参数。

所有参数必须有参数名。

不支持可变参数。

二、返回类型

用后置的方法书写返回类型,类似于普通函数的返回类型,如果不写返回类型,编译器会根据函数体中的代码推断出来。

如果有返回类型,建议显式的指定,自动推断可能与预期不一致。

三、函数体

类似于普通函数的函数体。

四、捕获列表

通过捕获列表,lambda函数可以访问父作用域中的非静态局部变量(静态局部变量可以直接访问,不能访问全局变量)。

捕获列表书写在[]中,与函数参数的传递类似,捕获方式可以是值和引用。

以下列出了不同的捕获列表的方式。

 

1)值捕获

与传递参数类似,采用值捕获的前提是变量可以拷贝。

与传递参数不同,变量的值是在lambda函数创建时拷贝,而不是调用时拷贝。

例如:

size_t v1 = 42;

auto f = [ v1 ] { return v1; }; // 使用了值捕获,将v1拷贝到名为f的可调用对象。

v1 = 0;

auto j = f(); // j为42,f保存了我们创建它是v1的拷贝。

由于被捕获的值是在lambda函数创建时拷贝,因此在随后对其修改不会影响到lambda内部的值。

默认情况下,如果以传值方式捕获变量,则在lambda函数中不能修改变量的值。

2)引用捕获

和函数引用参数一样,引用变量的值在lambda函数体中改变时,将影响被引用的对象。

size_t v1 = 42;

auto f = [ &v1 ] { return v1; }; // 引用捕获,将v1拷贝到名为f的可调用对象。

v1 = 0;

auto j = f(); // j为0。

如果采用引用方式捕获变量,就必须保证被引用的对象在lambda执行的时候是存在的。

3)隐式捕获

除了显式列出我们希望使用的父作域的变量之外,还可以让编译器根据函数体中的代码来推断需要捕获哪些变量,这种方式称之为隐式捕获。

隐式捕获有两种方式,分别是[=]和[&]。[=]表示以值捕获的方式捕获外部变量,[&]表示以引用捕获的方式捕获外部变量。

int a = 123;

auto f = [ = ] { cout

f(); // 输出:123

auto f1 = [ & ] { cout

f1(); //输出:123(采用了后++)

cout

4)混合方式捕获

lambda函数还支持混合方式捕获,即同时使用显式捕获和隐式捕获。

混合捕获时,捕获列表中的第一个元素必须是 = 或 &,此符号指定了默认捕获的方式是值捕获或引用捕获。

需要注意的是:显式捕获的变量必须使用和默认捕获不同的方式捕获。例如:

int i = 10;

int j = 20;

auto f1 = [ =, &i] () { return j + i; }; // 正确,默认值捕获,显式是引用捕获

auto f2 = [ =, i] () { return i + j; }; // 编译出错,默认值捕获,显式值捕获,冲突了

auto f3 = [ &, &i] () { return i +j; }; // 编译出错,默认引用捕获,显式引用捕获,冲突了

5)修改值捕获变量的值

在lambda函数中,如,但是,在lambda函数的外部,变量的值不会被修改。果以传值方式捕获变量,则函数体中不能修改该变量,否则会引发编译错误。

在lambda函数中,如果希望修改值捕获变量的值,可以加mutable选项

int a = 123;

auto f = amutable { cout cout

f(); // 输出:124

cout

6)异常说明

lambda可以抛出异常,用throw(…)指示异常的类型,用noexcept指示不抛出任何异常。

lambda函数的本质

当我们编写了一个lambda函数之后,编译器将它翻译成一个类,该类中有一个重载了()的函数。

1)采用值捕获

采用值捕获时,lambda函数生成的类用捕获变量的值初始化自己的成员变量。

例如:

int a =10;

int b = 20;

auto addfun = [=] (const int c ) -> int { return a+c; };

int c = addfun(b);

cout

等同于:

class Myclass

{

int m_a; // 该成员变量对应通过值捕获的变量。

public:

Myclass( int a ) : m_a(a){}; // 该形参对应捕获的变量。

// 重载了()运算符的函数,返回类型、形参和函数体都与lambda函数一致。

int operator()(const int c) const

{

return a + c;

}

};

默认情况下,由lambda函数生成的类是const成员函数,所以变量的值不能修改。如果加上mutable,相当于去掉const。这样上面的限制就能讲通了。

2)采用引用捕获

如果lambda函数采用引用捕获的方式,编译器直接引用就行了。

唯一需要注意的是,lambda函数执行时,程序必须保证引用的对象有效。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值