C++ lambda 表达式
外观
C++ Lambda表达式[编辑 | 编辑源代码]
Lambda表达式是C++11引入的一项强大特性,它允许在代码中定义匿名函数对象(也称为闭包)。Lambda表达式常用于简化代码、实现回调函数或在需要临时函数的场景中使用。
基本语法[编辑 | 编辑源代码]
Lambda表达式的基本语法如下:
[捕获列表](参数列表) -> 返回类型 { 函数体 }
其中:
- 捕获列表:指定lambda表达式可以访问的外部变量
- 参数列表:与普通函数的参数列表类似
- 返回类型:可选的,如果省略则由编译器自动推导
- 函数体:包含要执行的代码
最简单的Lambda示例[编辑 | 编辑源代码]
#include <iostream>
int main() {
auto greet = []() { std::cout << "Hello, World!"; };
greet(); // 调用lambda
return 0;
}
输出:
Hello, World!
捕获列表详解[编辑 | 编辑源代码]
Lambda表达式可以通过捕获列表访问外部变量,有以下几种捕获方式:
捕获方式 | 语法 | 描述 |
---|---|---|
值捕获 | [x] |
创建x的副本 |
引用捕获 | [&x] |
引用外部变量x |
隐式值捕获 | [=] |
以值方式捕获所有外部变量 |
隐式引用捕获 | [&] |
以引用方式捕获所有外部变量 |
混合捕获 | [=, &x] |
大部分变量值捕获,x引用捕获 |
捕获示例[编辑 | 编辑源代码]
#include <iostream>
int main() {
int x = 10, y = 20;
// 值捕获x,引用捕获y
auto lambda = [x, &y]() {
std::cout << "x: " << x << ", y: " << y << "\n";
y++; // 可以修改y,因为它是引用捕获
};
lambda();
std::cout << "After lambda, y is now: " << y << "\n";
return 0;
}
输出:
x: 10, y: 20 After lambda, y is now: 21
参数和返回类型[编辑 | 编辑源代码]
Lambda表达式可以像普通函数一样接受参数和指定返回类型。
带参数的Lambda[编辑 | 编辑源代码]
#include <iostream>
int main() {
auto add = [](int a, int b) { return a + b; };
std::cout << "5 + 3 = " << add(5, 3) << "\n";
return 0;
}
输出:
5 + 3 = 8
指定返回类型[编辑 | 编辑源代码]
当函数体包含多个返回语句且类型不同,或者返回类型不明显时,需要显式指定返回类型。
#include <iostream>
int main() {
auto divide = [](double a, double b) -> double {
if(b == 0) return 0; // 返回double而非int
return a / b;
};
std::cout << "10 / 3 = " << divide(10, 3) << "\n";
std::cout << "10 / 0 = " << divide(10, 0) << "\n";
return 0;
}
输出:
10 / 3 = 3.33333 10 / 0 = 0
通用Lambda (C++14)[编辑 | 编辑源代码]
C++14引入了通用Lambda,可以使用auto
作为参数类型。
#include <iostream>
int main() {
auto print = [](auto value) {
std::cout << value << "\n";
};
print(42); // int
print(3.14); // double
print("Hello"); // const char*
return 0;
}
输出:
42 3.14 Hello
初始化捕获 (C++14)[编辑 | 编辑源代码]
C++14允许在捕获列表中初始化变量,这在使用移动语义时特别有用。
#include <iostream>
#include <string>
#include <utility>
int main() {
std::string str = "Hello";
// 移动捕获str
auto lambda = [s = std::move(str)]() {
std::cout << s << "\n";
};
lambda();
std::cout << "str is now: " << str << "\n"; // str已被移动
return 0;
}
输出:
Hello str is now:
可变Lambda[编辑 | 编辑源代码]
默认情况下,值捕获的变量在lambda内是const的。使用mutable
关键字可以修改这些副本。
#include <iostream>
int main() {
int x = 0;
auto counter = [x]() mutable {
x++; // 修改副本
return x;
};
std::cout << counter() << "\n"; // 1
std::cout << counter() << "\n"; // 2
std::cout << "Original x: " << x << "\n"; // 仍然是0
return 0;
}
输出:
1 2 Original x: 0
实际应用案例[编辑 | 编辑源代码]
STL算法中的Lambda[编辑 | 编辑源代码]
Lambda表达式常用于STL算法中作为谓词。
#include <iostream>
#include <vector>
#include <algorithm>
int main() {
std::vector<int> numbers = {5, 2, 8, 1, 9, 3};
// 使用lambda排序
std::sort(numbers.begin(), numbers.end(), [](int a, int b) {
return a > b; // 降序排序
});
for(int n : numbers) {
std::cout << n << " ";
}
return 0;
}
输出:
9 8 5 3 2 1
异步编程中的回调[编辑 | 编辑源代码]
Lambda非常适合作为异步操作的回调函数。
#include <iostream>
#include <thread>
#include <chrono>
int main() {
std::cout << "Starting async operation...\n";
std::thread worker([]() {
std::this_thread::sleep_for(std::chrono::seconds(2));
std::cout << "Async operation completed!\n";
});
std::cout << "Main thread continues...\n";
worker.join();
return 0;
}
输出:
Starting async operation... Main thread continues... Async operation completed!
Lambda与函数指针[编辑 | 编辑源代码]
Lambda表达式可以转换为函数指针,前提是它不捕获任何变量。
#include <iostream>
void call_func(void (*func)(const char*)) {
func("Hello from function pointer");
}
int main() {
// 无捕获的lambda可以转换为函数指针
auto lambda = [](const char* msg) {
std::cout << msg << "\n";
};
call_func(lambda);
return 0;
}
输出:
Hello from function pointer
Lambda表达式的类型[编辑 | 编辑源代码]
每个Lambda表达式都有唯一的、未命名的类型。可以使用auto
或std::function
来存储Lambda。
使用std::function[编辑 | 编辑源代码]
#include <iostream>
#include <functional>
int main() {
std::function<int(int, int)> add = [](int a, int b) {
return a + b;
};
std::cout << "Sum: " << add(5, 3) << "\n";
return 0;
}
输出:
Sum: 8
性能考虑[编辑 | 编辑源代码]
Lambda表达式通常会被编译器内联,因此性能与普通函数相当。但是:
- 捕获大量变量会增加Lambda对象的大小
- 使用
std::function
会有轻微的性能开销 - 简单的无捕获Lambda可以像函数指针一样高效
总结[编辑 | 编辑源代码]
Lambda表达式是C++中强大的功能,它:
- 允许在需要的地方定义匿名函数
- 可以捕获上下文中的变量
- 语法简洁,适合与STL算法配合使用
- 在C++14和C++17中得到了进一步扩展
掌握Lambda表达式可以显著提高代码的可读性和表达力,特别是在函数式编程风格和异步编程中。