c++ Lambda匿名函数的用法
·
C++ Lambda 表达式是现代 C++ 中极其强大的特性,它允许在代码中内联定义匿名函数对象。以下是 Lambda 表达式的完整用法指南:
一、基本语法结构
[捕获列表] (参数列表) -> 返回类型 {
// 函数体
}
简化形式(根据上下文可省略部分):
[]{} // 最简单的lambda:无参数、无捕获、无返回类型
int x{ return x * x; } // 带参数的lambda
二、捕获列表详解
捕获列表定义了 Lambda 如何访问外部变量。
1. 值捕获 [=]
int a = 1, b = 2;
auto lambda = [=] {
return a + b; // 拷贝a和b的值
};
a = 10; // 修改外部a,不影响lambda内的拷贝值
std::cout << lambda(); // 输出 3
2. 引用捕获 [&]
int a = 1, b = 2;
auto lambda = [&] {
return a + b; // 引用a和b
};
a = 10; // 修改外部a,lambda内也会看到变化
std::cout << lambda(); // 输出 12
3. 混合捕获
int a = 1, b = 2, c = 3;
auto lambda = [=, &c] { // 值捕获a和b,引用捕获c
return a + b + c;
};
4. 显式指定捕获变量
int x = 1, y = 2, z = 3;
auto lambda1 = [x, &y] { /* 只捕获x(值)和y(引用) */ };
auto lambda2 = [=, &z] { /* 值捕获所有,但z用引用 */ };
auto lambda3 = [&, x] { /* 引用捕获所有,但x用值 */ };
5. 初始化捕获 (C++14)
int x = 10;
auto lambda = [value = x + 5] { // 用表达式初始化捕获变量
return value; // value = 15
};
// 移动语义捕获
auto unique_ptr = std::make_unique<int>(42);
auto lambda = [ptr = std::move(unique_ptr)] {
return *ptr;
};
三、参数列表与返回类型
1. 自动推导返回类型
// 编译器自动推导返回类型
auto square = int x { return x * x; }; // 返回int
auto print = [] { std::cout << "Hello"; }; // 返回void
2. 显式指定返回类型
// 需要显式指定返回类型的情况
auto complex = int x -> double {
if (x > 0) return x * 1.5;
else return x * 0.5; // 必须统一返回类型
};
3. 泛型 Lambda (C++14)
// 使用auto参数
auto generic = auto x, auto y { return x + y; };
std::cout << generic(1, 2); // 3
std::cout << generic(1.5, 2.5); // 4.0
4. 模板 Lambda (C++20)
// 使用模板语法
auto templateLambda = []<typename T>(T x, T y) {
return x + y;
};
四、Mutable Lambda
默认情况下,值捕获的变量在 Lambda 内是 const 的,使用 mutable 可以修改:
int counter = 0;
auto lambda = mutable {
counter++; // 修改拷贝的值
return counter;
};
std::cout << lambda(); // 1
std::cout << lambda(); // 2
std::cout << counter; // 0 (外部变量不变)
五、实际应用场景
1. STL 算法中的谓词
std::vector<int> numbers = {1, 2, 3, 4, 5};
// 查找大于3的第一个元素
auto it = std::find_if(numbers.begin(), numbers.end(),
int x { return x > 3; });
// 对每个元素平方
std::transform(numbers.begin(), numbers.end(), numbers.begin(),
int x { return x * x; });
// 排序:按绝对值大小
std::sort(numbers.begin(), numbers.end(),
int a, int b { return std::abs(a) < std::abs(b); });
2. 异步编程
#include <future>
#include <iostream>
std::future<int> asyncResult = std::async([]{
std::this_thread::sleep_for(std::chrono::seconds(1));
return 42;
});
std::cout << "Waiting for result...\n";
std::cout << "Result: " << asyncResult.get() << std::endl;
3. 事件处理与回调
class Button {
public:
void setOnClick(std::function<void()> callback) {
m_callback = std::move(callback);
}
void click() { if (m_callback) m_callback(); }
private:
std::function<void()> m_callback;
};
Button btn;
btn.setOnClick([]{
std::cout << "Button clicked!\n";
});
4. 资源管理 (RAII)
auto fileCloser = FILE* file {
if (file) fclose(file);
};
// 使用unique_ptr自定义删除器
std::unique_ptr<FILE, decltype(fileCloser)> file(
fopen("data.txt", "r"), fileCloser);
六、Lambda 的类型与存储
1. 使用 auto 推导
auto lambda = []{ return 42; };
// lambda的类型是编译器生成的唯一类型
2. 使用 std::function 包装
#include <functional>
std::function<int(int)> func = int x { return x * 2; };
// 可以存储任何可调用对象(函数、lambda、函数对象)
3. 作为函数参数传递
void processNumbers(const std::vector<int>& nums,
std::function<bool(int)> predicate) {
for (int n : nums) {
if (predicate(n)) {
std::cout << n << " ";
}
}
}
processNumbers({1, 2, 3, 4, 5}, int x { return x % 2 == 0; });
七、C++20 新特性
1. 无状态 Lambda 可默认构造
auto lambda = []{ return 42; };
decltype(lambda) lambda2; // C++20 允许:无捕获的lambda可默认构造
2. 模板参数支持
// 模板参数列表
auto lambda = []<typename T>(const std::vector<T>& vec) {
return vec.size();
};
3. concepts 支持
auto lambda = []<std::integral T>(T x) {
return x * 2;
};
八、最佳实践与注意事项
-
避免过度使用引用捕获:
// 危险:可能悬空引用 int* data = new int[100]; auto dangerous = [&] { use(data); }; delete[] data; // data成为悬空引用 dangerous(); // 未定义行为! -
优先使用值捕获(除非需要修改外部变量):
int value = 42; auto safe = [value] { return value + 10; }; // 安全 -
复杂逻辑考虑命名 Lambda:
auto complexOperation = const auto& data { // 复杂的多行逻辑 if (data.empty()) return false; return std::all_of(data.begin(), data.end(), int x { return x > 0; }); }; -
性能关键代码避免
std::function:// 直接使用auto推导的类型(无开销) auto efficient = []{ /* ... */ }; // std::function有类型擦除开销 std::function<void()> lessEfficient = []{ /* ... */ };
完整示例:Lambda 综合应用
#include <iostream>
#include <vector>
#include <algorithm>
#include <functional>
int main() {
std::vector<int> numbers = {5, 2, 8, 1, 9, 3};
// 1. 排序:按奇偶性然后大小
std::sort(numbers.begin(), numbers.end(), int a, int b {
bool a_even = (a % 2 == 0);
bool b_even = (b % 2 == 0);
if (a_even != b_even) {
return a_even; // 偶数在前
}
return a < b; // 同奇偶性按数值排序
});
// 2. 过滤并处理:输出大于4的数的平方
std::for_each(numbers.begin(), numbers.end(), int x {
if (x > 4) {
std::cout << x * x << " ";
}
});
// 3. 可变Lambda计数器
int callCount = 0;
auto countingLambda = int x mutable {
callCount++;
return x * 2;
};
std::cout << "\nCalled " << callCount << " times\n";
return 0;
}
输出结果:
25 64 81
Called 0 times
Lambda 表达式让 C++ 的函数式编程变得极其便利和强大!
更多推荐
所有评论(0)