c++ lambda表达式
在 C++ 11 中,lambda 表达式(通常称为 “lambda”)是一种在被调用的位置或作为参数传递给函数的位置定义匿名函数对象的简便方法。 Lambda 通常用于封装传递给算法或异步方法的少量代码行。
lambda的组成部分
-
Capture 子句(在 C++ 规范中也称为 lambda 引导。)
-
参数列表(可选)。 (也称为 lambda 声明符)
-
可变规范(可选)。
-
异常规范(可选)。
-
尾随返回类型(可选)。
-
“lambda 体”
lambda表达式又被称作lambda函数,匿名函数。当一个函数,你觉得不需要第二次用到它,你就可以把它写成lambda函数,因为你没必要给他起一个名字,只要能实现功能就行。
Capture 子句(捕获列表)
[ ] 空捕获列表,不捕获任何变量
[=] 拷贝捕获
[&] 引用捕获
[=, &] 拷贝与引用混合
[names] names是一个逗号分隔的名字列表,这些名字都是lambda所在函数的局部变量。
[this] 捕获 this 指针
[ ] 空捕获列表,不捕获任何变量**
举例:
#include <iostream>
using namespace std;
int main()
{
int i = 1024;
auto func = [](int i) { // (int i) 是指传入改匿名函数的参数
cout << i;
};
func(i);
}
vs报错:
error C3493: 无法隐式捕获“i”,因为尚未指定默认捕获模式
error C2064: 项不会计算为接受 0 个参数的函数
改正:
#include <iostream>
using namespace std;
int main()
{
int i = 1024;
auto func = [](int i) { // (int i) 是指传入改匿名函数的参数
cout << i;
};
func(i); //这里将i作为函数参数传入
return 0;
}
又如下:输出Hello World
#include <iostream>
int main()
{
[] {
std::cout << "Hello,World" << std::endl;
}();
return 0;
}
[=] 拷贝捕获
#include <iostream>
using namespace std;
int main()
{
int i = 1024;
auto func = [=] { // [=] 表明将外部的所有变量拷贝一份到该函数内部
cout << i << endl;
};
func();
return 0;
}
[&] 引用捕获
#include <iostream>
using namespace std;
int main()
{
int i = 1024;
cout << &i << endl;
auto fun1 = [&] {
cout << &i << endl;
};
fun1();
return 0;
}
运行:
[=, &] 拷贝与引用混合
#include <iostream>
using namespace std;
int main()
{
int i = 1024, j = 2048;
cout << "i:" << &i << endl;
cout << "j:" << &j << endl;
auto fun1 = [=, &i] { // 默认拷贝外部所有变量,但引用变量 i
cout << "i:" << &i << endl;
cout << "j:" << &j << endl;
};
fun1();
return 0;
}
运行:
[names] 指定引用或拷贝
names是一个逗号分隔的名字列表,这些名字都是lambda所在函数的局部变量。
例1
#include <iostream>
using namespace std;
int main()
{
int i = 1024, j = 2048;
cout << "outside i value:" << i << " addr:" << &i << endl;
auto fun1 = [i] {
cout << "inside i value:" << i << " addr:" << &i << endl;
// cout << j << endl; // j 未捕获
};
fun1();
return 0;
}
例2
#include <iostream>
using namespace std;
int main()
{
int i = 1024, j = 2048;
cout << "outside i value:" << i << " addr:" << &i << endl;
auto fun1 = [&i] {
cout << "inside i value:" << i << " addr:" << &i << endl;
// cout << j << endl; // j 未捕获
};
fun1();
return 0;
}
例3:
#include <iostream>
using namespace std;
int main()
{
int i = 1024, j = 2048, k;
cout << "outside i:" << &i << endl;
cout << "outside j:" << &j << endl;
auto fun1 = [i, &j] {
cout << "inside i:" << &i << endl;
cout << "inside j:" << &j << endl;
// cout << k; // k 未捕获
};
fun1();
return 0;
}
[this] 捕获 this 指针
#include <iostream>
using namespace std;
class test
{
public:
void hello() {
cout << "test hello!" << endl;
};
void lambda() {
auto fun = [this] { // 捕获了 this 指针
this->hello(); // 这里 this 调用的就是 class test 的对象了
};
fun();
}
};
int main()
{
test t;
t.lambda();
return 0;
}
输出:test hello!
lambda表达式的嵌套
#include <iostream>
int main()
{
using namespace std;
// The following lambda expression contains a nested lambda
// expression.
int timestwoplusthree = [](int x) { return [](int y) { return y * 2; }(x)+3; }(5);
// Print the result.
cout << timestwoplusthree << endl;
}
运行结果:输出13
可变lambda
默认情况下,对于一个值被拷贝的变量,lambda不会改变其值,如果我们希望能改变一个被捕获变量的值,就必须在参数列表尾加上关键字mutable。
如果加上mutable,则会使得该“值捕获变量”的值,可以在被捕获的值的基础上进行变化(注意是能修改拷贝,而不是值本身)。
例如:
#include <iostream>
using namespace std;
int main()
{
size_t t = 9;
auto f = [t]() mutable {return ++t; };
cout << f() << endl;
cout << f() << endl;
t = 0;
cout << "after assign t=0, f() is: " << f() << endl;
cout << "t:" << t << endl;
return 0;
}
运行结果:
在捕获变量列表中值捕获的变量t,它其实可以被看做函数对象f的一个数据成员变量,其初始值为9,因此,函数体内对其每次的变动都会被累积。
指定lambda返回类型
1.不指定返回类型的情况。返回类型为void时,或者只有一个return,编译器就可以自动推导,而无需指定
auto func_1=[] (int I) {return I;}; //编译器推断返回类型为int型
auto func_2=[] (int I) {cout<<I<<endl;}; //编译器推断返回类型为void型,也就是lambda不返回任何值;
2.必须指定返回类型的情况
当lambda函数体内包含不止一个return语句时,编译器就不能推断其返回类型。例如:
auto func_3 = [](int I) {
if (I < 0)
return 0;
else
return 1;
}; //虽然两个return语句都返回int型,
//但编译器不能推断出其返回类型,所以该语句会产生编译错误。
auto func_3 = [](int I) -> int {
if (I < 0)
return 0;
else
return 1;
}; //指定返回类型必须采用尾置返回类型(即-> type的形式)
lambda抛出异常
#include<iostream>
using namespace std;
int main() // C4297 expected
{
[]() noexcept { throw 5; }();
}
参考:
https://www.cnblogs.com/findumars/p/8062299.html
https://blog.youkuaiyun.com/liunan199481/article/details/83657299?utm_source=app
https://blog.youkuaiyun.com/Trouble_provider/article/details/90521215
https://www.cnblogs.com/smiler/p/4095723.html
https://blog.youkuaiyun.com/liukang325/article/details/53610869
https://docs.microsoft.com/zh-cn/cpp/cpp/lambda-expressions-in-cpp?view=vs-2019