1. Lambda 表达式的高级用法
1.1 捕获初始化
C++14 引入了 Lambda 表达式捕获初始化(capture initialization),允许你在捕获列表中直接初始化工厂函数。这使得可以在 Lambda 中捕获和初始化变量。
#include <iostream>
int main() {
int a = 10;
// 使用捕获初始化
auto lambda = [b = a + 5]() {
std::cout << "b = " << b << std::endl; // b 在捕获时初始化为 a + 5
};
lambda(); // 输出: b = 15
return 0;
}
1.2 使用 mutable
关键字
默认情况下,Lambda 捕获的变量(通过引用或值)是常量的。如果你想在 Lambda 函数内修改捕获的变量,需要使用 mutable
关键字。
#include <iostream>
int main() {
int x = 10;
auto lambda = [x]() mutable {
x += 5;
std::cout << "Inside lambda: " << x << std::endl; // 输出: 15
};
lambda();
std::cout << "Outside lambda: " << x << std::endl; // 输出: 10 (x 仍然是 10)
return 0;
}
1.3 Lambda 返回值类型推导
在某些情况下,你可能希望明确地指定 Lambda 的返回类型,特别是当有多个返回路径并且编译器无法推导出返回类型时。可以使用尾返回类型(trailing return type)来指定。
#include <iostream>
int main() {
auto lambda = [](int x, int y) -> int {
return x + y;
};
std::cout << "Sum: " << lambda(3, 4) << std::endl; // 输出: Sum: 7
return 0;
}
1.4 参数包与变长参数
你可以利用 Lambda 表达式的参数包特性来处理可变参数列表。这在现代 C++ 中与特征匹配(template metaprogramming)一起使用非常方便。
#include <iostream>
#include <initializer_list>
auto sum = [](std::initializer_list<int> list) {
int total = 0;
for (auto value : list) {
total += value;
}
return total;
};
int main() {
std::cout << "Sum: " << sum({1, 2, 3, 4, 5}) << std::endl; // 输出: Sum: 15
return 0;
}
2. 不常见的 Lambda 语法
2.1 关联状态的 Lambda
可以在 Lambda 表达式中存放状态和行为。可以通过捕获语法来维护状态信息。这在某些需要保持状态的回调函数中很有用。
#include <iostream>
#include <vector>
#include <algorithm>
int main() {
std::vector<int> nums = {1, 3, 2, 5, 4};
// 以状态保持为目标的 Lambda
std::sort(nums.begin(), nums.end(), [count = 0](int a, int b) mutable {
count++;
std::cout << "Comparison count: " << count << std::endl;
return a < b;
});
for (int num : nums) {
std::cout << num << " "; // 输出: 1 2 3 4 5
}
std::cout << std::endl;
return 0;
}
2.2 递归 Lambda
C++14 允许 Lambda 是可递归的,通过捕获自身的方式来实现这一点。
#include <iostream>
int main() {
// 递归 Lambda 计算阶乘
std::function<int(int)> factorial = [](int n) -> int {
return (n <= 1) ? 1 : n * factorial(n - 1);
};
int result = factorial(5);
std::cout << "Factorial of 5: " << result << std::endl; // 输出: Factorial of 5: 120
return 0;
}
2.3 Lambda 作为模板参数
在 C++20 中,Lambda 可以作为模板参数,支持更灵活的编程模式。你可以在模板中直接使用 Lambda。
#include <iostream>
template<typename Func>
void applyLambda(Func func) {
func();
}
int main() {
auto myLambda = []() { std::cout << "Hello, Lambda as template argument!" << std::endl; };
applyLambda(myLambda); // 输出: Hello, Lambda as template argument!
return 0;
}
2.4 Lambda 与 std::bind
结合
可以将 Lambda 与 std::bind
结合使用,在处理复杂的回调时使代码更加灵活。
#include <iostream>
#include <functional>
int main() {
auto add = [](int x, int y) { return x + y; };
auto boundAdd = std::bind(add, std::placeholders::_1, 10); // 绑定第二个参数为 10
std::cout << "Result: " << boundAdd(5) << std::endl; // 输出: Result: 15
return 0;
}
最后
Lambda 函数在现代 C++ 中是一个非常强大的特性,通过灵活的捕获机制和多种不常见的语法选项,Lambda 能够实现许多高效灵活的编程风格。从捕获初始化到递归调动,Lambda 的高级用法完全展现了其灵活与强大的潜力。
使用 Lambda,你可以将程序逻辑更加模块化和透明,为代码加上更清晰的语义。随着 C++ 的不断发展,Lambda 函数及其相关特性的增多,程序员有了更多的工具来编写简洁且高效的代码。
没有回复内容