C++笔记 Lambda表达式
Lambda 表达式是 C++11 引入的一项强大特性,它允许你在需要一个函数的地方内联定义一个匿名函数。你可以把它理解为一个 “一次性” 的、临时的函数,非常适合用于编写简短、只在局部使用的代码片段,尤其是在结合 STL 算法时。
为什么需要 Lambda 表达式?
在 Lambda 出现之前,如果想给 std::sort 或 std::for_each 这样的算法传递一个自定义的比较或操作逻辑,你通常需要:
- 定义一个全局函数:这会污染全局命名空间,而且函数可能只在一个地方使用。
- 定义一个函数对象(Functor):代码结构相对复杂,需要创建一个类。
Lambda 表达式解决了这些问题,它让代码:
- 更简洁:将函数逻辑直接写在使用它的地方,无需额外定义。
- 更清晰:读者可以在调用点立即看到函数的实现,而不需要跳转到其他地方。
- 更灵活:可以方便地捕获(capture)周围作用域的变量。
Lambda 表达式的语法
Lambda 表达式的语法可以分解为以下几个部分:
[capture-clause] (parameters) -> return-type { body }
让我们逐一解析:
-
[capture-clause](捕获子句): 这是 Lambda 表达式最核心的特性之一。它定义了 Lambda 可以从其外围作用域(即定义 Lambda 的函数或代码块)中捕获哪些变量,以及如何捕获(值捕获或引用捕获)。[]: 空捕获列表。Lambda 不捕获任何外部变量。[=]: 以值传递的方式捕获所有外部变量。Lambda 内部会创建这些变量的副本。[&]: 以引用传递的方式捕获所有外部变量。Lambda 内部使用的是这些变量的引用。[var]: 以值传递的方式捕获指定变量var。[&var]: 以引用传递的方式捕获指定变量var。[this]: 在类的成员函数中,捕获当前对象的指针this,允许 Lambda 访问类的成员变量和成员函数。[=, &var]: 以值传递捕获所有外部变量,但对var变量使用引用传递。[&, var]: 以引用传递捕获所有外部变量,但对var变量使用值传递。
-
(parameters)(参数列表): 这和普通函数的参数列表类似。如果 Lambda 没有参数,可以省略这部分。(): 无参数。
-
-> return-type(返回类型): 这部分指定了 Lambda 表达式的返回类型。在很多情况下,编译器可以根据return语句自动推导返回类型,因此这部分也可以省略。- 如果 Lambda 体中包含多个
return语句,且返回类型不同,编译器可能无法推导,此时必须显式指定返回类型。
- 如果 Lambda 体中包含多个
-
{ body }(函数体): 这是 Lambda 表达式的执行代码块,和普通函数体一样。
2. 完整的Lambda语法分解
cpp
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
void basicSyntax() {
cout << "=== Lambda表达式完整语法 ===" << endl;
// 1. 最简单的lambda - 无参数,无返回值推导
auto lambda1 = []() {
cout << "Hello Lambda!" << endl;
};
lambda1();
// 2. 带参数的lambda
auto lambda2 = [](int a, int b) {
return a + b;
};
cout << "5 + 3 = " << lambda2(5, 3) << endl;
// 3. 显式指定返回类型
auto lambda3 = [](double a, double b) -> double {
return a / b;
};
cout << "10.0 / 3.0 = " << lambda3(10.0, 3.0) << endl;
// 4. 参数可以auto推导 (C++14)
auto lambda4 = [](auto a, auto b) {
return a + b;
};
cout << "auto参数: " << lambda4(5, 3.5) << endl; // 8.5
}
3. 捕获列表详解
捕获列表是Lambda最强大的特性之一,它决定了Lambda如何访问外部变量。
值捕获 vs 引用捕获
cpp
void captureDemo() {
cout << "\n=== 捕获列表详解 ===" << endl;
int x = 10;
int y = 20;
string name = "C++";
// 1. 值捕获 [=] 或具体变量
auto value_capture = [x, y]() {
cout << "值捕获: x=" << x << ", y=" << y << endl;
// x = 100; // 错误!值捕获的变量是const的
};
value_capture();
// 2. 引用捕获 [&] 或具体变量
auto ref_capture = [&x, &name]() {
cout << "引用捕获修改前: x=" << x << ", name=" << name << endl;
x = 100;
name = "Lambda";
cout << "引用捕获修改后: x=" << x << ", name=" << name << endl;
};
ref_capture();
cout << "外部变量也被修改: x=" << x << ", name=" << name << endl;
// 3. 混合捕获
auto mixed_capture = [x, &y, name]() {
cout << "混合捕获: x(值)=" << x << ", y(引用)=" << y << ", name(值)=" << name << endl;
y = 200; // 可以修改引用捕获的变量
};
mixed_capture();
cout << "y被修改为: " << y << endl;
// 4. 默认捕获
int a = 1, b = 2, c = 3;
// 默认值捕获 [=]
auto default_by_value = [=]() {
cout << "默认值捕获: a=" << a << ", b=" << b << ", c=" << c << endl;
};
default_by_value();
// 默认引用捕获 [&]
auto default_by_ref = [&]() {
a++; b++; c++;
cout << "默认引用捕获修改: a=" << a << ", b=" << b << ", c=" << c << endl;
};
default_by_ref();
cout << "外部变量: a=" << a << ", b=" << b << ", c=" << c << endl;
}
可变Lambda (mutable)
cpp
void mutableLambda() {
cout << "\n=== 可变Lambda (mutable) ===" << endl;
int count = 0;
// 没有mutable - 值捕获的变量是const
// auto lambda1 = [count]() {
// count++; // 错误!不能修改值捕获的变量
// };
// 使用mutable - 可以修改值捕获的变量(但修改的是副本)
auto lambda2 = [count]() mutable {
count++;
cout << "内部count: " << count << endl;
return count;
};
cout << "调用前外部count: " << count << endl;
lambda2(); // 内部count: 1
lambda2(); // 内部count: 2
lambda2(); // 内部count: 3
cout << "调用后外部count: " << count << endl; // 仍然是0!
// 引用捕获不需要mutable
auto lambda3 = [&count]() {
count++;
cout << "引用捕获修改count: " << count << endl;
};
lambda3(); // count: 1
lambda3(); // count: 2
cout << "最终外部count: " << count << endl; // 2
}
4. 初始化捕获 (C++14)
cpp
void initCapture() {
cout << "\n=== 初始化捕获 (C++14) ===" << endl;
int x = 100;
// 1. 在捕获时初始化变量
auto lambda1 = [value = x + 50]() {
cout << "初始化捕获: value = " << value << endl;
};
lambda1();
// 2. 移动语义捕获
auto unique_ptr = make_unique<int>(42);
auto lambda2 = [ptr = move(unique_ptr)]() {
if (ptr) {
cout << "移动捕获的值: " << *ptr << endl;
}
};
lambda2();
// cout << *unique_ptr << endl; // 错误!unique_ptr已经被移动
// 3. 引用初始化捕获
string name = "Hello";
auto lambda3 = [&ref = name]() {
ref += " World";
cout << "引用初始化捕获: " << ref << endl;
};
lambda3();
cout << "外部name: " << name << endl;
}
5. Lambda在STL算法中的应用
cpp
#include <algorithm>
#include <numeric>
#include <vector>
void stlWithLambda() {
cout << "\n=== Lambda在STL算法中的应用 ===" << endl;
vector<int> numbers = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
// 1. for_each
cout << "for_each: ";
for_each(numbers.begin(), numbers.end(), [](int n) {
cout << n << " ";
});
cout << endl;
// 2. find_if - 查找第一个偶数
auto it = find_if(numbers.begin(), numbers.end(), [](int n) {
return n % 2 == 0;
});
if (it != numbers.end()) {
cout << "第一个偶数: " << *it << endl;
}
// 3. count_if - 统计满足条件的元素
int count = count_if(numbers.begin(), numbers.end(), [](int n) {
return n > 5;
});
cout << "大于5的元素个数: " << count << endl;
// 4. transform - 转换元素
vector<int> squared(numbers.size());
transform(numbers.begin(), numbers.end(), squared.begin(), [](int n) {
return n * n;
});
cout << "平方后的数组: ";
for (int n : squared) cout << n << " ";
cout << endl;
// 5. sort - 自定义排序
vector<string> words = {"apple", "banana", "cherry", "date", "elderberry"};
sort(words.begin(), words.end(), [](const string& a, const string& b) {
return a.length() < b.length(); // 按长度排序
});
cout << "按长度排序: ";
for (const auto& word : words) cout << word << " ";
cout << endl;
// 6. accumulate - 自定义累加操作
vector<int> values = {1, 2, 3, 4, 5};
int product = accumulate(values.begin(), values.end(), 1, [](int a, int b) {
return a * b;
});
cout << "乘积: " << product << endl;
}
6. 泛型Lambda (C++14)
cpp
void genericLambda() {
cout << "\n=== 泛型Lambda (C++14) ===" << endl;
// 1. 使用auto参数
auto generic_add = [](auto a, auto b) {
return a + b;
};
cout << "int加法: " << generic_add(5, 3) << endl; // 8
cout << "double加法: " << generic_add(2.5, 3.7) << endl; // 6.2
cout << "string连接: " << generic_add(string("Hello"), string(" World")) << endl;
// 2. 在STL算法中使用泛型Lambda
vector<int> ints = {1, 2, 3};
vector<double> doubles = {1.1, 2.2, 3.3};
vector<string> strings = {"a", "b", "c"};
auto print_vector = [](const auto& vec) {
for (const auto& item : vec) {
cout << item << " ";
}
cout << endl;
};
cout << "整数向量: ";
print_vector(ints);
cout << "浮点数向量: ";
print_vector(doubles);
cout << "字符串向量: ";
print_vector(strings);
}
7. Lambda作为返回值和高阶函数
cpp
void higherOrderFunctions() {
cout << "\n=== Lambda作为返回值和高阶函数 ===" << endl;
// 1. 返回Lambda的函数
auto create_multiplier = [](int factor) {
return [factor](int value) {
return value * factor;
};
};
auto double_it = create_multiplier(2);
auto triple_it = create_multiplier(3);
cout << "10的双倍: " << double_it(10) << endl; // 20
cout << "10的三倍: " << triple_it(10) << endl; // 30
// 2. 接受Lambda作为参数的函数
auto process_numbers = [](const vector<int>& nums, auto processor) {
vector<int> result;
for (int n : nums) {
result.push_back(processor(n));
}
return result;
};
vector<int> numbers = {1, 2, 3, 4, 5};
auto squared = process_numbers(numbers, [](int n) { return n * n; });
auto incremented = process_numbers(numbers, [](int n) { return n + 10; });
cout << "平方: ";
for (int n : squared) cout << n << " ";
cout << endl;
cout << "加10: ";
for (int n : incremented) cout << n << " ";
cout << endl;
// 3. 函数组合
auto compose = [](auto f, auto g) {
return [f, g](auto x) {
return f(g(x));
};
};
auto add_two = [](int x) { return x + 2; };
auto times_three = [](int x) { return x * 3; };
auto add_then_multiply = compose(times_three, add_two);
auto multiply_then_add = compose(add_two, times_three);
cout << "先加2再乘3: " << add_then_multiply(5) << endl; // (5+2)*3 = 21
cout << "先乘3再加2: " << multiply_then_add(5) << endl; // (5*3)+2 = 17
}
8. Lambda的实际应用场景
场景1:回调函数
cpp
#include <functional>
#include <vector>
class Button {
private:
string label;
vector<function<void()>> click_handlers;
public:
Button(string lbl) : label(lbl) {}
void onClick(function<void()> handler) {
click_handlers.push_back(handler);
}
void click() {
cout << "按钮 '" << label << "' 被点击!" << endl;
for (const auto& handler : click_handlers) {
handler();
}
}
};
void callbackExample() {
cout << "\n=== 回调函数场景 ===" << endl;
Button btn("提交");
int click_count = 0;
// 使用Lambda作为回调
btn.onClick([&click_count]() {
click_count++;
cout << "点击次数: " << click_count << endl;
});
btn.onClick([]() {
cout << "执行提交操作..." << endl;
});
// 模拟点击
btn.click();
btn.click();
}
场景2:资源管理
cpp
#include <fstream>
#include <memory>
void resourceManagement() {
cout << "\n=== 资源管理场景 ===" << endl;
// 1. 使用Lambda进行RAII式资源管理
auto file_processor = [](const string& filename) {
ifstream file(filename);
if (!file.is_open()) {
return -1;
}
// Lambda确保文件在作用域结束时关闭
return [file = move(file)]() mutable -> int {
string line;
int line_count = 0;
while (getline(file, line)) {
cout << "第" << ++line_count << "行: " << line << endl;
}
return line_count;
};
};
// 2. 使用Lambda创建自定义删除器
auto custom_deleter = [](FILE* file) {
if (file) {
fclose(file);
cout << "文件已关闭" << endl;
}
};
unique_ptr<FILE, decltype(custom_deleter)> file_ptr(
fopen("test.txt", "w"),
custom_deleter
);
if (file_ptr) {
fputs("Hello Lambda!", file_ptr.get());
}
}
场景3:线程和异步编程
cpp
#include <thread>
#include <future>
#include <chrono>
void asyncProgramming() {
cout << "\n=== 异步编程场景 ===" << endl;
// 1. 在线程中使用Lambda
vector<thread> threads;
for (int i = 0; i < 3; ++i) {
threads.emplace_back([i]() {
this_thread::sleep_for(chrono::milliseconds(100 * i));
cout << "线程 " << i << " 执行完成" << endl;
});
}
for (auto& t : threads) {
t.join();
}
// 2. 使用async和Lambda
auto future1 = async(launch::async, []() {
this_thread::sleep_for(chrono::seconds(1));
return string("异步任务1完成");
});
auto future2 = async(launch::async, []() {
this_thread::sleep_for(chrono::milliseconds(500));
return string("异步任务2完成");
});
cout << future2.get() << endl;
cout << future1.get() << endl;
}
9. Lambda的性能和最佳实践
cpp
void performanceAndBestPractices() {
cout << "\n=== 性能考虑和最佳实践 ===" << endl;
// 1. 避免不必要的捕获
int important_data = 42;
vector<int> large_data = {1, 2, 3, 4, 5};
// 不好:捕获了整个large_data的拷贝
// auto bad_lambda = [=]() { ... };
// 好:只捕获需要的变量
auto good_lambda = [&important_data, data_ref = ref(large_data)]() {
cout << "重要数据: " << important_data << endl;
// 使用data_ref而不是拷贝large_data
};
// 2. 使用constexpr Lambda (C++17)
constexpr auto constexpr_lambda = [](int n) constexpr {
return n * n;
};
constexpr int result = constexpr_lambda(5); // 编译期计算
cout << "编译期计算: " << result << endl;
// 3. 立即调用Lambda
int x = [](int a, int b) {
return a + b;
}(10, 20); // 立即调用
cout << "立即调用结果: " << x << endl;
// 4. 使用std::function存储Lambda
function<int(int, int)> func_store = [](int a, int b) {
return a * b;
};
cout << "function存储: " << func_store(6, 7) << endl;
}
10. C++17/20中的Lambda新特性
cpp
void modernLambdaFeatures() {
cout << "\n=== C++17/20 Lambda新特性 ===" << endl;
// 1. constexpr Lambda (C++17)
constexpr auto square = [](int n) constexpr {
return n * n;
};
static_assert(square(5) == 25);
// 2. 捕获*this (C++17)
struct Processor {
int value = 100;
auto get_lambda() {
// C++17前:捕获this指针
// return [this]() { return value; };
// C++17:捕获*this的拷贝
return [*this]() mutable {
value += 10;
return value;
};
}
};
// 3. 模板Lambda (C++20)
#if __cplusplus >= 202002L
auto template_lambda = []<typename T>(T a, T b) {
return a + b;
};
cout << "模板Lambda: " << template_lambda(5, 3) << endl;
#endif
// 4. 默认构造和赋值 (C++20)
auto simple = [](int x) { return x * 2; };
decltype(simple) simple_copy; // C++20允许默认构造
simple_copy = simple; // C++20允许赋值
}
总结
Lambda表达式的核心优势:
-
简洁性:内联定义,代码更紧凑
-
灵活性:捕获外部变量,创建闭包
-
性能:通常可以被编译器内联优化
-
功能性:支持泛型、常量表达式等
关键语法要点:
-
[]捕获列表:控制对外部变量的访问 -
()参数列表:与普通函数相同 -
mutable:允许修改值捕获的变量 -
constexpr:编译期计算 -
-> return_type:显式指定返回类型
最佳实践:
-
尽量使用值捕获,避免意外的副作用
-
对于大型对象,使用引用捕获或初始化捕获
-
在性能关键路径考虑使用Lambda
-
合理使用泛型Lambda提高代码复用性
掌握Lambda表达式是现代C++编程的重要技能!
更多推荐



所有评论(0)