Lambda表达式的用法
Lambda 表达式是 C++11 引入的一种匿名函数(即没有名字的函数),用于简化代码,尤其适用于 回调函数、STL 算法、并行计算 等场景。
1. 基本语法
[捕获列表](参数列表) -> 返回类型 { // 函数体 };
- [捕获列表] : 捕获外部变量(类似闭包)
- (参数列表) : 传递参数
- -> 返回类型 : 可选, 指定返回值类型(C++14可自动推导)
- { // 函数体 } : 函数的具体实现
# 在C++中,如果Lambda表达式没有参数,且作为函数参数传递时,括号()是可以省略的。
# 这是因为编译器可以根据上下文推断出Lambda表达式没有参数。
# 比如在条件变量中,lambda表达式无参数时,通常省略()
# 如:cv.wait(lock, [] { return flag });
2. 最简单的Lambda
Lambda 允许我们定义一个 匿名函数:
#include <iostream>
using namespace std;
#if 0 //最简单的用法
int main()
{
// 让变量 func 存储这个 Lambda,并可以调用。
auto func = [](){ cout << "Hello, World!" <<endl;};
// auto func = []() -> int{ cout << "Hello, World!" <<endl; return 0;}; //有返回值
func(); //调用lambda
return 0;
}
#endif
#if 1 //传递参数
int main()
{
auto func = [](int a, int b){
cout << "Hello, World!" <<endl;
return a + b; // C++14自动推导返回值
};
int ret = func(1, 1);
cout << "ret = " << ret << endl;
return 0;
// [](int a, int b) { return a + b; } 是一个 匿名加法函数。
}
#endif
3. 捕获变量
Lambda 可以 捕获作用域外的变量,让它们在 Lambda 内部可用。
3.1 按值捕获
按值捕获时,Lambda 内部是 拷贝 外部变量:
#include <iostream>
using namespace std;
#if 1 //捕获外部变量, 按值捕获
int main()
{
int val = 100;
int val2 = 1000;
auto add_val = [val](int a){ // 捕获指定的外部变量
// val = 999; // 报错:error: assignment of read-only variable ‘val’
// cout << val << endl; // 编译会报错
return a + val;
};
int ret = add_val(1);
cout << "add_val ret = " << ret << endl;
auto add_all_val = [=](int a){ // [=] 是捕获列表,表示捕获当前作用域中的所有变量(按值捕获)
return a + val + val2;
};
int ret2 = add_all_val(1);
cout << "add_all_val ret = " << ret2 << endl;
return 0;
}
#endif
注意:按值捕获后,Lambda 无法修改 捕获的外部变量,因为是拷贝。
3.2 按引用捕获
如果希望 Lambda 内部可以 修改外部变量,可以用 引用捕获:
#include <iostream>
using namespace std;
#if 1 //捕获外部变量, 按引用捕获
int main()
{
int val = 100;
int val2 = 1000;
auto add_val = [&val](int a){ // 捕获指定的外部变量的引用,可以修改其值
val += 1;
return a + val;
};
int ret = add_val(1);
cout << "add_val ret = " << ret << ", val = "<< val << endl;
auto add_all_val = [=](int a){ // [&] 是捕获列表,表示捕获当前作用域中的所有变量(按引用捕获)
return a + val + val2;
};
int ret2 = add_all_val(1);
cout << "add_all_val ret = " << ret2 << endl;
return 0;
}
#endif
注意:[&]
让 Lambda **直接修改 **捕获的外部变量,不会拷贝。
4. Lambda作为std::function
Lambda 也可以用 std::function
存储:
#include <iostream>
#include <functional>
using namespace std;
int main()
{
std::function<int(int,int)> multiply = [](int a, int b){
return a * b;
};
cout << "multiply(4, 5) = " << multiply(4, 5) << endl;
return 0;
}
为什么用 std::function
?
- 适用于 回调函数 和 多态函数存储。
- 允许 Lambda 作为 参数传递。
5. Lambda作为回调函数
在 回调函数 中,Lambda 非常有用。例如:
#if 0
#include <iostream>
using namespace std;
typedef void (*testCb)(int);
void process(int num, testCb callback)
{
cout << "num is: " << num << endl;
callback(num);
}
int main()
{
process(10, [](int num){
cout << "callback ret = " << num * num << endl;
});
return 0;
}
#endif
#if 1
#include <iostream>
#include <vector>
#include <algorithm>
int main() {
std::vector<int> numbers = {1, 5, 3, 8, 2};
// 使用 Lambda 作为排序规则(降序)
std::sort(numbers.begin(), numbers.end(), [](int a, int b) {
return a > b;
});
for (int num : numbers) {
std::cout << num << " "; // 输出:8 5 3 2 1
}
return 0;
}
#endif
6. Lambda返回类型
通常 Lambda 可以自动推导返回类型,但如果返回值类型不同,就要 手动指定:
#include <iostream>
#if 0
int main() {
// 这里 -> double 指定了返回类型,否则 C++ 会推导为 int(因为 a 和 b 都是 int)。
auto divide = [](int a, int b) -> double {
return (double)a / b;
};
// 输出 3.33333
std::cout << "10 / 3 = " << divide(10, 3) << std::endl;
return 0;
}
#endif
#if 1
int main() {
auto divide = [](int a, int b) -> int {
return (double)a / b;
};
// 输出 3
std::cout << "10 / 3 = " << divide(10, 3) << std::endl;
return 0;
}
#endif
7. Lambda在std::thread
Lambda 也可以用于 多线程:
#include <iostream>
#include <thread>
int main() {
std::thread t([]() {
std::cout << "Lambda 线程正在运行..." << std::endl;
});
t.join(); // 等待线程执行完毕
return 0;
}
8. Lambda用于类成员函数
在类中,Lambda 可以用于 成员函数:
#include <iostream>
class MyClass {
public:
void run() {
auto print = [this]() { // [this] 允许 Lambda 访问类的成员变量和函数。
std::cout << "Lambda 访问类的成员变量 mVal = " << mVal << std::endl;
};
print();
printInfo();
};
void printInfo() { std::cout << "Lambda 调用类的成员函数 printInfo() !" << std::endl;};
private:
int mVal = 10;
};
int main() {
MyClass obj;
obj.run();
return 0;
}
# 输出
Lambda 访问类的成员变量 mVal = 10
Lambda 调用类的成员函数 printInfo() !
9. 总结
Lambda 语法 | 说明 |
---|---|
[](){} | 无参数,无返回值 |
[](int a, int b) { return a + b; } | 传递参数 |
[=](){} | 按值捕获(拷贝外部变量) |
[&](){} | 按引用捕获(修改外部变量) |
[this](){} | 访问类成员 |
[](int a, int b) -> double { return (double)a / b; } | 指定返回类型 |
std::function<int(int)> f = [](int a){ return a * 2; }; | 存储到 std::function |
std::thread t([]() { std::cout << "线程"; }); | 用于 std::thread |
Lambda 在 回调函数、多线程、STL 算法、类成员函数 等场景特别有用!