Lambda 表达式是C++11引入的新特性。Lambda 表达式允许你在代码中创建匿名函数(或闭包),而不需要单独定义函数。它提供了一种更简洁和方便的方式来编写可调用对象,并且可以捕获外部变量,使得在函数对象中可以使用外部作用域的变量。
1. 基本语法
Lambda 表达式的基本语法如下:
[capture](params) opt -> ret {body;};
- capture:捕获列表,用于捕获外部变量,可以是值捕获、引用捕获或混合捕获。
- params:参数列表,与普通函数的参数类似。
- ret:返回类型,用 `->` 指定,可以省略,编译器会自动推导返回类型。
- body:函数体内的代码。
Lambda 表达式的引入使得C++程序员能够更加方便地编写高阶函数、在算法中使用自定义操作,以及在多线程编程中处理并发操作。Lambda 表达式大大提高了C++语言的表达能力和灵活性。
2. 捕获列表
2.1 值捕获
捕获外部变量的值,Lambda函数内部无法修改该变量
int x = 42;
auto lambda = [x]() {
std::cout << "Captured value: " << x << std::endl;
};
2.2 引用捕获
捕获外部变量的引用,Lambda函数内部可以修改该变量
int y = 42;
auto lambda = [&y]() {
y++;
std::cout << "Modified reference: " << y << std::endl;
};
2.3 隐式捕获
使用 `=` 捕获外部作用域的所有变量(值捕获),或使用 `&` 捕获所有变量的引用
int a = 1, b = 2;
auto lambda1 = [=]() {
std::cout << "Captured value a: " << a << std::endl;
std::cout << "Captured value b: " << b << std::endl;
};
auto lambda2 = [&]() {
a++;
b++;
std::cout << "Modified reference a: " << a << std::endl;
std::cout << "Modified reference b: " << b << std::endl;
};
在捕获列表中,你可以混合使用值捕获、引用捕获和隐式捕获,以适应不同的需求。捕获列表提供了灵活的机制,使得Lambda函数能够访问并操作外部作用域的变量。
还有几种不太常用的捕获方式, 了解下格式即可:
[=, &foo] - 按值捕获外部作用域中所有变量, 并按照引用捕获外部变量 foo
[this] - 捕获当前类中的this指针
让lambda表达式拥有和当前类成员函数同样的访问权限
如果已经使用了 & 或者 =, 默认添加此选项
3. 函数本质
Lambda 函数(Lambda expression)是C++中一种匿名函数的表示方式。它允许你在代码中创建简单的函数,而无需像传统函数那样单独定义一个函数名。Lambda 函数的本质实际上是一个可调用的对象,或者说是一个函数对象(function object)。
Lambda 函数背后的实现原理主要涉及以下几个关键概念:
3.1 闭包(Closure)
Lambda 函数可以捕获外部作用域的变量,形成闭包。捕获的变量被保存在Lambda函数内部,使得Lambda函数可以在其定义的作用域外部访问这些变量。Lambda 函数通过闭包实现了对外部变量的访问。
3.2 仿函数(Functor)
Lambda 函数实际上是一个函数对象,类似于传统的仿函数,可以像函数一样被调用。Lambda 函数在内部重载了函数调用运算符 operator(),使得它可以像函数一样被调用。
3.3 编译器生成的匿名类
在编译时,C++编译器会为Lambda 函数生成一个匿名类,并在其中实现Lambda 函数的功能。这个类内部包含捕获的变量,并提供了函数调用运算符的重载,使得Lambda 函数可以被调用。
Lambda 函数的本质可以看作是一个带有函数调用运算符重载的匿名类对象,这个对象包含了Lambda 函数的行为定义以及捕获的外部变量。Lambda 函数的简洁语法和灵活性使得它成为C++中一个强大的编程工具,特别适用于简单的、局部性的操作。
4. 应用
Lambda 表达式在C++中有许多应用场景,主要体现在以下几个方面:
4.1 STL 算法
Lambda 表达式可以用作STL(Standard Template Library)算法的谓词(predicate),即用于定义元素的比较、筛选、变换等操作。它使得使用STL算法更加灵活。
std::vector<int> numbers = {1, 2, 3, 4, 5};
// 使用 Lambda 表达式对容器中的元素进行平方操作
std::transform(numbers.begin(), numbers.end(), numbers.begin(), [](int x) { return x * x; });
4.2 函数对象
Lambda 表达式可以替代传统的函数对象(Functor)或者函数指针,用于自定义排序、查找等操作。Lambda 表达式在这种情况下可以减少代码的冗余,提高可读性。
std::sort(numbers.begin(), numbers.end(), [](int a, int b) { return a > b; });
4.3 事件处理和回调函数
在事件驱动的程序中,Lambda 表达式可以作为回调函数,用于处理事件
button.onClick([]() { std::cout << "Button clicked!" << std::endl; });
4.4 多线程编程
Lambda 表达式在多线程编程中非常有用,可以方便地将任务传递给线程,简化了多线程编程的代码。
std::thread t1([]() { std::cout << "Thread 1" << std::endl; });
std::thread t2([]() { std::cout << "Thread 2" << std::endl; });
t1.join();
t2.join();
4.5 智能指针和资源管理
在使用智能指针时,Lambda 表达式可以用于自定义删除器,用于在指针释放时执行特定的操作。
std::shared_ptr<int> ptr(new int, [](int* p) { std::cout << "Deleting pointer..." << std::endl; delete p; });
这些只是 Lambda 表达式的一些基本应用场景,实际上,在C++的各种编程场景中,Lambda 表达式都可以大显身手,使得代码更加简洁和灵活。