✨博客主页:何曾参静谧的博客
📌文章专栏:「C/C++」C/C++程序设计
相关术语
Lambda表达式:
是C++11
引入的一种函数对象
,可以方便地创建匿名函数。与传统的函数不同,Lambda表达式可以在定义时直接嵌入代码,无需单独定义函数名称、参数和返回类型等信息。Lambda表达式通常用于需要定义一些简单的回调函数或者函数对象。优点:简洁
、效率高
、更加灵活
。
一、语法格式
//Lambda表达式的语法如下:
[capture-list] (parameter-list) opt -> return-type { function-body }
[捕获列表](参数列表) 函数选项 -> 返回值类型{函数体};
//示例代码:
auto ret = [](int a,int b) -> int {
return a + b;
};
1.1、捕获列表[capture-list]
[]
- 不捕捉任何变量[&]
- 捕获外部作用域中所有变量,并作为引用在函数体内使用 (按引用捕获
)[=]
- 捕获外部作用域中所有变量,并作为副本在函数体内使用 (按值捕获
)
– 拷贝的副本在匿名函数体内部是只读的
[=, &foo]
- 按值捕获外部作用域中所有变量,并按照引用捕获外部变量 foo[bar]
- 按值捕获 bar 变量,同时不捕获其他变量[&bar]
- 按引用捕获 bar 变量,同时不捕获其他变量[this]
- 捕获当前类中的 this 指针
– 让 lambda 表达式拥有和当前类成员函数同样的访问权限
– 如果已经使用了 & 或者 =, 默认添加此选项
1.2、参数列表(parameter-list)
其中,parameter-list可以包含以下内容:
空参数列表:
(),表示没有任何参数。普通参数列表:
(int a, double b)。可变参数列表:
(int a, double b, …),表示可以接受任意数量的参数。
//例如,以下Lambda表达式将接受两个整数作为参数,并返回它们的和:
auto lambda = [](int a, int b) -> int { return a + b; };
1.3、 函数选项(opt)可省略
mutable:
可以修改按值传递进来的拷贝(注意是能修改拷贝,而不是值本身)一般和[=]一起
exception:
指定函数抛出的异常,如抛出整数类型的异常,可以使用 throw ();
1.4、返回类型 -> return-type
标识函数返回值的类型,当返回值为 void,或者函数体中只有一处 return 的地方(此时编译器可以自动推断出返回值类型)时,这部分可以省略
//例如,以下Lambda表达式将接受两个整数作为参数,并返回它们的和:
auto lambda = [](int a, int b) { return a + b; };
1.5、函数体 { function-body }
函数的实现,这部分
不能省略
,但函数体可以为空
,可以包含任意数量的语句
。
//例如,以下Lambda表达式将按值捕获变量x和y,并返回它们的和:
int x = 1, y = 2;
auto lambda = [=]() -> int {
int sum = x + y;
return sum;
};
二、使用Lambda表达式
Lambda表达式可以像普通函数一样使用,可以赋值给函数对象、作为函数参数或返回值等。下面是一些使用Lambda表达式的示例:
2.1、赋值给函数对象
可以将Lambda表达式赋值给函数对象,以便在其他地方使用。
#include <iostream>
#include <functional>
int main()
{
std::function<int(int, int)> add = [](int a, int b) -> int {
return a + b;
};
std::cout << add(1, 2) << std::endl; // 输出3
return 0;
}
2.2、作为函数参数
可以将Lambda表达式作为函数参数传递,用于定义回调函数等。
#include <iostream>
#include <vector>
#include <algorithm>
int main()
{
std::vector<int> vec = {1, 2, 3, 4, 5};
// 使用Lambda表达式定义判断是否为偶数的函数对象
auto is_even = [](int n) -> bool {
return n % 2 == 0;
}; // 注意这里要添加分号
// 使用std::count_if算法统计偶数个数
int count = std::count_if(vec.begin(), vec.end(), is_even);
std::cout << count << std::endl; // 输出2
return 0;
}
2.3、作为返回值
可以将Lambda表达式作为函数的返回值,用于动态生成函数对象。
#include <iostream>
#include <functional>
std::function<int(int, int)> create_adder(int n){
// 使用Lambda表达式动态生成函数对象
return [n](int x, int y) -> int {
return n + x + y;
};
}
int main(){
auto adder = create_adder(10);
std::cout << adder(1, 2) << std::endl; // 输出13
return 0;
}
2.4、匿名函数
//这个匿名函数只是被定义,不会被调用。
[](){
cout << "这是一个Lamada匿名函数";
};
//匿名函数定义+调用。
[](){
cout << "这是一个Lamada匿名函数";
}();
// 匿名函数的定义+调用:
int ret = [](int a) -> int
{
return a+1;
}(100); // 100是传递给匿名函数的参数
// 在匿名函数外部定义变量
int a=1, b=2, c=3;
// 调用匿名函数
[](){
// 打印外部变量的值
cout << "a:" << a << ", b: " << b << ", c:" << c; // error, 不能使用任何外部变量
};
[&](){
cout << "使用引用的方式传递数据: ";
cout << "a+1:" << a++ << ", b+c= " << b+c;
}();
// 值拷贝的方式使用外部数据
[=](int m, int n)mutable{
cout << "使用拷贝的方式传递数据: ";
// 拷贝的外部数据在函数体内部是只读的, 如果不添加 mutable 关键字是不能修改这些只读数据的值的
// 添加 mutable 允许修改的数据是拷贝到函数内部的副本, 对外部数据没有影响
cout << "a+1:" << a++ << ", b+c= " << b+c;
cout << "m+1: " << ++m << ", n: " << n;
}(1, 2);