C++ 11 Lambda表达式

具体例子见LeetCode第133场周赛

在LeetCode第133场周赛打完铁(做对了一个==),看神犇们的解答时发现了在sort里有一块没见过的神操作

sort(costs.begin(),costs.end(),[](vector<int> &a,vector<int> &b){
    return a[0] - a[1] < b[0] - b[1];
});

仔细一看又有点眼熟,查了查原来就是平时程序中那一大段取消cin,cout连接的Lambda表达式1,查了一下详细用法,这里记录下来

//就是这个
static const auto io_sync_off = []() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    return nullptr;
}();

捕获子句部分基本参考2 ,其余根据MSDN个人整理3 ,刚开始理解难免有错误欢迎指正

Lambda表达式是C++11引入的特性,是一种描述函数对象的机制,它的主要应用是描述某些具有简单行为的函数。Lambda也可以称为匿名函数

Lambda 表达式的各部分

Lambda表达式完整的声明格式如下:

[capture list] (parameter list) mutable exception -> return type { function body }

在这里插入图片描述

各项具体含义:

  1. capture list:捕获外部变量列表
  2. parameter list:参数列表
  3. mutable:用来说用是否可以修改捕获的变量
  4. exception:异常设定
  5. return type:返回类型
  6. function body:函数体

捕获子句

Lambda表达式可以访问或捕获周边范围变量。 Lambda 以 capture 子句开头,它指定哪些变量被捕获,以及捕获是通过值或引用。

1.空

空 capture 子句 [ ] 指示 lambda 表达式的主体不访问封闭范围中的变量。

2.值捕获

传递值,相当于以复制的形式传入

int a = 123;
auto print = [a]() {
    cout << a << endl;
};
a = 456;
print(); //输出123
3.引用捕获

也就是平时所说的传引用

int a = 123;
auto print = [&a]() {
    cout << a << endl;
};
a = 456;
print(); //输出456
4.隐式捕获

上面的值捕获和引用捕获都需要我们在捕获列表中显示列出Lambda表达式中使用的外部变量。除此之外,我们还可以让编译器根据函数体中的代码来推断需要捕获哪些变量,这种方式称之为隐式捕获。隐式捕获有两种方式,分别是 [=][&][=] 表示以值捕获的方式捕获外部变量, [&] 表示以引用捕获的方式捕获外部变量。

值捕获

int a = 123;
auto print = [=]() {
    cout << a << endl;
};
a = 456;
print(); //123

引用捕获

int a = 123;
auto print = [&]() {
    cout << a << endl;
};
a = 456;
print(); //456
5、混合方式

多种捕获方式可以共存

a 以引用捕获,其他以值捕获,注意一定要 = 在前,也就是先确定所有,再特殊个别

int a = 123;
int b = 456;
auto print = [=, &a]() {
    cout << a << " " << b << endl;
};
a = 789;
print(); //789 456

b 以值捕获,其他以引用捕获

int a = 123;
int b = 456;
auto print = [&, b]() {
    cout << a << " " << b << endl;
};
a = 789;
print(); //789 456

参数列表

除了捕获变量,lambda 还可接受输入参数。

1.通过传递参数

auto print = [](int a, int b) {
    cout << a << " " << b << endl;
    return a + b;
};
cout << print(1, 2); //输出1 2\n 3

2.直接赋值调用

auto print = [](int a, int b) {
    cout << a << " " << b << endl;
    return a + b;
}(1, 2);	   //输出1 2\n 3
cout << print; //这里的print就相当于一个int变量了,不能加括号

并且在C++ 14,如果参数类型是泛型,则可以使用 auto 关键字作为类型说明符。

lambda 表达式可以将另一个 lambda 表达式作为其自变量。(都是坑,待填)

可变规范

使用mutable关键字可以改变以值捕获方式传进的变量,但是不会改变变量本身的值

int a = 666;
auto print = [=]() mutable {
    a = 999;			//可以改变,但不会改变a本身的值
    cout << a << endl;
};
print();	// 999
cout << a;  // 666

异常规范

你可以使用 noexcept 异常规范来指示 lambda 表达式不会引发任何异常(不会)

[]() noexcept { throw 5; }();

返回类型

编译器将自动推导 Lambda 表达式的返回类型:

1.如果函数体中存在return语句,编译器将从返回表达式的类型推导返回类型

2.如果函数体中没有return语句,则返回值为void类型

3.lambda 表达式可以生成另一个 lambda 表达式作为其返回值

返回int

auto fun = [](int a) {
    return a;
};

当然也不是能推断出所有的返回类型,错误的例子

auto fun = [] {
    return {1, 2};
};
//报错a brace-enclosed list does not provide a return type for this lambda
//大括号括起来的列表不提供此lambda的返回类型

解决方法

//返回一个具体的类型
auto fun = [] {
    return make_pair(1, 2);
};
//或规定其返回类型,注意加上小括号
auto fun = []() -> pair<int, int> {
    return {1, 2};
};

函数体

其实上面的例子并没有体现出lambda表达式的特殊性,之所以叫匿名函数,就是可以不规定其名称,但是其可以像函数一样运行

cout << [](int a, int b) {
    cout << a << " " << b << endl;
    return a + b;
}(1, 2) 
	 << endl;  //输出1 2\n 3

也可以捕获变量进行操作:引用隐式捕获m,值显示捕获n,赋值a = 4,并且n可变

int n = 0, m = 0;
[&, n](int a) mutable {
    m = ++n + a;
}(4);
cout << n << " " << m << endl; //输出0 5
具体作用

目前来说就sort函数下可以利用lambda表达式来减少代码量

比如周赛题中的排序

bool cmp(vector<int> &a, vector<int> &b)
{
    return a[0] - a[1] < b[0] - b[1];
}
sort(costs.begin(), costs.end(), cmp);

就可以用lambda表达式直接代替

sort(costs.begin(), costs.end(), [](vector<int> &a, vector<int> &b){
    return a[0] - a[1] < b[0] - b[1];
});

参考资料:


  1. 解析 static auto x = []() { std::ios::sync_with_stdio(false);std::cin.tie(nullptr);return 0;}() ↩︎

  2. C++ 11 Lambda表达式:dsw846 ↩︎

  3. MSDN:lambda-expressions ↩︎

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值