在 C++ 98/03 时代,我们主要依靠函数指针和仿函数(Function Object)来传递行为:
cpp复制编辑boolisEven(int x) {
return x % 2 == 0;
}
随着 C++11 的到来,引入了强大的 Lambda 表达式,让我们可以像 Python、JavaScript 一样优雅地定义 匿名函数、闭包函数和高阶函数。
Lambda 表达式使得 C++ 函数式编程成为可能,成为现代 C++ 的重要特性。
cpp复制编辑[capture](parameters) -> return_type {
function_body;
}
cpp复制编辑auto add = [](int a, int b) -> int {
return a + b;
};
std::cout << add(3, 4); // 输出 7
cpp复制编辑auto multiply = [](int a, int b) {
return a * b;
};
捕获外部变量的方式:
捕获方式 | 含义 |
---|---|
[=] | 值捕获所有外部变量 |
[&] | 引用捕获所有外部变量 |
[x] | 值捕获变量 x |
[&x] | 引用捕获变量 x |
[=, &y] | 默认值捕获,但 y 使用引用 |
[this] | 捕获当前对象指针(用于类中) |
cpp复制编辑int x = 10;
auto f = [x]() { return x + 1; }; // 捕获副本auto g = [&x]() { x += 1; }; // 修改 x
Lambda 表达式其实是一个匿名类的 闭包对象(Closure Object),它重载了 operator(),因此可像函数一样调用。
cpp复制编辑auto lambda = [](int x) { return x * x; };
等价于:
cpp复制编辑struct__lambda {
intoperator()(int x) const {
return x * x;
}
};
C++20 引入 decltype(auto) 和 concept,更好支持 Lambda 类型。
Lambda 与 STL 算法完美契合,提升代码表达力。
cpp复制编辑std::vector<int> v = {1, 2, 3};
std::for_each(v.begin(), v.end(), [](int x) {
std::cout << x << " ";
});
cpp复制编辑std::vector<int> v = {3, 1, 4};
std::sort(v.begin(), v.end(), [](int a, int b) {
return a > b;
});
cpp复制编辑int count = std::count_if(v.begin(), v.end(), [](int x) {
return x % 2 == 0;
});
默认情况下,捕获变量为只读,若想修改值副本,需加 mutable。
cpp复制编辑int x = 10;
auto f = [x]() mutable {
x += 1; // 修改副本,不影响外部 xreturn x;
};
f(); // 返回 11
std::cout << x; // 仍为 10
Lambda 不能直接推导类型,需要使用 std::function 或 auto。
cpp复制编辑#include<functional>std::function<int(int)> makeAdder(int base) {
return [base](int x) {
return base + x;
};
}
auto add5 = makeAdder(5);
std::cout << add5(3); // 输出 8
cpp复制编辑voidexecute(const std::function<void()> &func) {
func();
}
execute([] {
std::cout << "Hello from Lambda!" << std::endl;
});
在类中使用 Lambda:
cpp复制编辑classPrinter {
public:
voidrun() {
int count = 3;
auto printer = [this, count]() {
for (int i = 0; i < count; ++i)
std::cout << "Value: " << i + value << std::endl;
};
printer();
}
private:
int value = 10;
};
捕获 [this] 让 Lambda 可访问成员变量。
Lambda 本身无法直接递归调用自己,可以通过 std::function 或 Y Combinator 技巧实现。
cpp复制编辑std::function<int(int)> fib = [&](int n) {
return (n <= 1) ? n : fib(n - 1) + fib(n - 2);
};
或者更现代写法(C++14):
cpp复制编辑auto fib = [](auto self, int n) -> int {
return (n <= 1) ? n : self(self, n - 1) + self(self, n - 2);
};
std::cout << fib(fib, 6); // 输出 8
cpp复制编辑#include<thread>intmain() {
int x = 42;
std::thread t([x]() {
std::cout << "Thread value: " << x << std::endl;
});
t.join();
}
在多线程任务中,Lambda 极其便捷地绑定任务上下文。
cpp复制编辑auto f = [] (int x) { return x * x; }; // 无捕获int (*fp)(int) = f; // OK
cpp复制编辑std::unique_ptr<int> up = std::make_unique<int>(10);
auto lambda = [ptr = std::move(up)]() {
std::cout << *ptr << std::endl;
};
此技术称为 初始化捕获,C++14 起支持,C++20 支持 =std::move(...)。
text复制编辑int a = 10, b = 20;
auto f = [a, &b]() mutable {
a++; // 修改副本,不影响外部
b++; // 修改引用,影响外部
};
图示:
markdown复制编辑Lambda 对象:
--------------------------| a(副本) = 10 || b(引用) → 外部 b |
--------------------------
cpp复制编辑auto make_filter = [](int threshold) {
return [threshold](int x) {
return x > threshold;
};
};
auto filter10 = make_filter(10);
std::cout << filter10(15); // true
std::cout << filter10(5); // false
该 Lambda 工厂函数生成高阶条件过滤器。
特性 | 支持版本 | 描述 |
---|---|---|
Lambda 表达式 | C++11 | 匿名函数支持 |
mutable Lambda | C++11 | 修改值捕获副本 |
初始化捕获 | C++14 | [val = expr] |
泛型 Lambda | C++14 | [ ](auto x){} |
捕获 by move | C++20 | [ptr = std::move(...) ] |
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。