前言
总结记录自己学习并使用 C++ Lambda 表达式笔记。
Lambda 表达式概述
Lambda表达式是C++11新特性,用于创建匿名的函数对象,简化编程工作。
语法
[函数对象参数] (操作符重载函数参数)mutable或exception声明 ->返回类型{函数体}
其中返回值类型可隐式推导,void类型返回值可省略。
函数对象参数定义了Lambda如何访问作用域内的变量。
1. 函数对象参数
标示一个Lambda表达式的开始,必须存在,不能省略。函数参数对象只能使用那些定义 Lambda 所在作用范围内可见的局部变量(包含Lambda所在类的this)
a. []:没有任何函数参数对象
b. [=]:以值传递方式捕获Lambda所在范围内的所有局部变量。
c. [&]:以引用传递方法捕获Lambda所在范围内的所有局部变量。
d. this:函数体可以使用Lambda所在类的成员变量。
e. [x,&y]:x以值传递捕获,y以引用形式捕获。
f. [=,&z]:z以引用形式捕获,其他变量以值传递捕获。
g. [&,x]:x以值传递形式捕获,其他变量以引用形式捕获。
lambda要访问所在函数的局部变量时,必须先捕获。两种局部变量捕获方式:
值捕获:创建lambda表达式时,拷贝所在函数的局部变量的值。
引用捕获:创建lambda表达式时,获取变量的引用。需要确保lambda使用变量时,变量对应对象存在。
注:
1)值捕获是发生在lambda创建时,而非调用时。
2)lambda无法捕获任何static变量、全局变量,不过可以在lambda表达式内部直接访问。
#include <iostream>
using namespace std;
// 值捕获拷贝变量,发生在lambda创建时
void lambda_value()
{
int v1 = 1024;
auto a = [v1]()->int { return v1; }; // 值捕获v1 = 1024
v1 = 0;
auto b = a(); // lambda调用时,不会改变捕获值,因此b为1024
cout<<b<<endl;
}
// 引用捕获获取变量引用
void lambda_reference()
{
int v1 = 1024;
auto a = [&v1]()->int { return v1; }; // 引用捕获v1
v1 = 0;
auto b = a(); // b为0
cout<<b<<endl;
}
int main(int argc, const char * argv[])
{
lambda_value();
lambda_reference();
return 0;
}
2. 操作符重载函数参数
参数列表,标识重载的()操作符,没有参数时,可以省略,但"()"不可用省略,类似于函数定义。参数可以使用值传递和引用传递。
3. mutable 或者 exception 声明
可以省略。函数参数按值传递时,加上mutable修饰后,可以修改传递进来的拷贝。exception声明用于指定函数抛出的异常,可以使用throw(int)。
void lambda_mutable()
{
int v1 = 1023;
auto f = [v1]() mutable { return ++v1; }; // 加上mutable才能修改值捕获的v1
// <=> auto f = [v1]() mutable -> int { return ++v1; };
v1 = 0;
auto val = f(); // val 为1024
cout<<val<<endl;
}
4. -> 返回值类型
标识函数返回值的类型,当返回值为void,或者函数体中只有一处return的地方时,这部分可以省略,编译器自动推断返回类型。如果编译器无法推断lambda返回类型,就需要尾置返回类型,不可省略。
5. 函数体
标识函数的实现,不能省略,函数体可以为空。
简单例子
之前写过一篇 vector中pair的排序方法 的文章里面有用到 Lambda 表达式。
vector中pair的排序方法
下面同样给出一个类似的例子:
#include"iostream"
#include"vector"
#include"algorithm"
using namespace std;
static bool cmp(int &a, int &b)
{
return a > b;
}
int main()
{
vector<int> data;
for(unsigned int i = 0; i < 10; i++) {
data.push_back(i);
}
for(unsigned int i = 0; i < data.size(); ++i) {
cout << data[i] << endl;
}
//sort(data.begin(), data.end(), cmp);
sort(data.begin(), data.end(), [](int &a,int &b)->bool { return a>b;});
for_each(data.begin(), data.end(), [](int & d){ cout<<d<<endl;});
return 0;
}
总结
熟能生巧, 多写多用。