1.目的
Lambda 表达式是 C++11 引入的一种特性,旨在提供一种简洁的方式来定义和使用匿名函数。Lambda 表达式可以直接在代码中定义和使用,不需要像普通函数那样在其它地方声明和定义。
2.基本语法
Lambda 表达式的基本语法如下:
[capture](parameters) -> return_type { body }
• capture:捕获列表,指定哪些变量可以在 Lambda 表达式中使用。
• parameters:参数列表,与普通函数的参数列表类似。
• return_type:返回类型,可以省略,编译器会自动推断。
• body:函数体,与普通函数的函数体类似。
3.示例
3.1 无参
#include <iostream>
int main() {
auto lambda = []() {
std::cout << "Hello, Lambda!" << std::endl;
};
lambda(); // 调用 Lambda 表达式
return 0;
}
3.2 带参数
#include <iostream>
int main() {
auto add = [](int a, int b) -> int {
return a + b;
};
std::cout << "Sum: " << add(3, 5) << std::endl;
return 0;
}
3.3 带捕获列表
捕获列表用于指定哪些变量可以在 Lambda 表达式中使用。捕获列表有几种方式:
• [=]:按值捕获所有外部变量。
• [&]:按引用捕获所有外部变量。
• [this]:捕获当前对象的 this 指针。
• [a, &b]:按值捕获 a,按引用捕获 b。
#include <iostream>
int main() {
int x = 10;
int y = 20;
auto lambda1 = [=]() {
std::cout << "x: " << x << ", y: " << y << std::endl;
};
auto lambda2 = [&]() {
x = 30; // 可以修改 x
std::cout << "x: " << x << ", y: " << y << std::endl;
};
lambda1();
lambda2();
return 0;
}
3.4 返回类型
3.4.1自动推断
#include <iostream>
int main() {
auto add = [](int a, int b) {
return a + b; // 返回类型自动推断为 int
};
std::cout << "Sum: " << add(3, 5) << std::endl;
return 0;
}
3.4.2 显式指定
#include <iostream>
int main() {
auto divide = [](int a, int b) -> double {
return static_cast<double>(a) / b;
};
std::cout << "Division: " << divide(10, 3) << std::endl;
return 0;
}
3.5 Lambda 表达式在标准库中的应用
如 std::sort、std::for_each 等算法。
#include <iostream>
#include <vector>
#include <algorithm>
int main() {
std::vector<int> vec = {1, 2, 3, 4, 5};
// 使用 Lambda 表达式对 vector 元素进行排序
std::sort(vec.begin(), vec.end(), [](int a, int b) {
return a > b; // 降序排序
});
// 使用 Lambda 表达式输出 vector 元素
std::for_each(vec.begin(), vec.end(), [](int n) {
std::cout << n << " ";
});
return 0;
}
4.注意事项
4.1 捕获的生命周期
捕获的变量在 Lambda 表达式的生命周期内必须有效。如果捕获的是局部变量且 Lambda 表达式在其作用域外使用,可能会导致未定义行为。错误示例:
auto lambda;
{
int x = 10;
lambda = [x]() {
std::cout << x << std::endl; // 未定义行为
};
}
lambda(); // x 已经超出作用域
4.2 捕获的方式
int x = 10;
auto lambda = [x]() mutable {
x = 20; // 允许修改 x
std::cout << x << std::endl;
};
lambda();
std::cout << x << std::endl; // 原始 x 未修改
4.3 Lambda 表达式的类型
Lambda 表达式没有类型名,但可以使用 auto 或 std::function 来存储 Lambda 表达式
#include <iostream>
#include <functional>
int main() {
auto lambda = [](int a, int b) {
return a + b;
};
std::function<int(int, int)> func = lambda;
std::cout << "Sum: " << func(3, 5) << std::endl;
return 0;
}
4.4 使用mutable修饰
5.C14 扩展
5.1 捕获右值
在 C++14 之前的 C++11 中,Lambda 表达式只能捕获左值,不能直接捕获右值。这意味着如果你想要捕获一个右值,你必须先将其存储在一个局部变量中,然后捕获这个局部变量。
C++11 示例
#include <iostream>
#include <string>
int main() {
std::string str = "Hello";
auto lambda = [str]() mutable { std::cout << str << std::endl; }; // 捕获左值
lambda();
return 0;
}
在 C++14 中,Lambda 表达式可以直接捕获右值,通过 std::move 来实现移动捕获。这大大简化了代码,并且提高了性能,因为避免了不必要的拷贝。
C++14 示例
void function()
{
auto uniquePtr = std::make_unique<int>(1);
auto add = [v1 = 1, v2 = std::move(uniquePtr)](int x, int y) -> int {
return x + y + v1 + (*v2);
};
}
5.2 泛型 Lambda
void function()
{
auto add = [](auto x, auto y) {
return x+y;
};
std::cout << add(1, 2) << std::endl;
std::cout << add(1.1, 1.2) << std::endl;
}