1.Lambda 表达式:提供简单的方式定义匿名函数对象
1.2函数语法
[capture_clause] (parameters) -> return_type {
// 函数体
}
1.3函数参数分析
1.3.1 [capture_clause]: 定义了 lambda 表达式从其所在作用域中捕获哪些变量以及如何捕获(值捕获或引用捕获)
值捕获:创建变量的副本。
1.lambda内部使用的是外部变量的拷贝
2.外部变量的修改不会影响lambda内部的副本
3.lambda内部对副本的修改不会影响外部变量
引用捕获:使用变量的引用
1.lambda内部直接操作外部变量
捕获情况
[]:不捕获任何变量。 [=]:通过值捕获所有外部变量。
[&]:通过引用捕获所有外部变量。
[x, &y]:通过值捕获 x,通过引用捕获 y。
[=, &z]:通过值捕获所有外部变量,但通过引用捕获 z。
[&, a]:通过引用捕获所有外部变量,但通过值捕获 a。
[this]:捕获所在的类对象的 this 指针,从而可以访问类成员。
1.3.2 (parameters): 和普通函数的参数列表一样(可选)
1.3.3 -> return_type: 可以省略,编译器会自动推导(可选)。但在某些复杂情况下需要显式指定。
// 完整语法
[capture] (parameters) -> return_type { body }
// 省略返回类型(编译器推导)
[capture] (parameters) { body }
// 省略参数(无参数)
[capture] { body }
// 省略捕获和参数(最简单的lambda)
[] { std::cout << "Hello" << std::endl; }
可省略情况:当 lambda 函数体只有一个 return 语句,或者所有返回路径返回相同类型时,编译器可以自动推导返回类型
#include <iostream>
int main() {
// 情况1:单一return语句 - 可以省略
auto lambda1 = [](int a, int b) { // 省略 -> int
return a + b; // 编译器推导为 int
};
// 情况2:多个return,但类型相同 - 可以省略
auto lambda2 = [](int x) { // 省略 -> int
if (x > 0) {
return x * 2;
} else {
return x * 3; // 都是 int 类型
}
};
// 情况3:void 返回类型 - 可以省略
auto lambda3 = [](const std::string& msg) { // 省略 -> void
std::cout << msg << std::endl;
// 没有return语句,推导为void
};
std::cout << lambda1(5, 3) << std::endl; // 输出: 8
std::cout << lambda2(5) << std::endl; // 输出: 10
lambda3("Hello"); // 输出: Hello
return 0;
}
不可省略情况:当编译器无法自动推导返回类型时,必须显式指定。
#include <iostream>
#include <vector>
int main() {
// 情况1:多个return语句返回不同类型 - 必须显式指定
// auto ambiguous_lambda = [](bool flag) {
// if (flag) {
// return 10; // int
// } else {
// return 3.14; // double → 错误!类型不一致
// }
// };
// 正确:显式指定返回类型为 double
auto good_lambda1 = [](bool flag) -> double {
if (flag) {
return 10; // int 转换为 double
} else {
return 3.14; // double
}
};
// 情况2:递归lambda - 必须显式指定
// auto factorial = [](int n) {
// if (n <= 1) return 1;
// return n * factorial(n - 1); // 错误!编译器还不知道返回类型
// };
// 正确:使用 std::function 或显式指定类型
auto factorial = [](int n) -> int {
if (n <= 1) return 1;
return n * factorial(n - 1); // 现在可以了
};
std::cout << good_lambda1(true) << std::endl; // 输出: 10
std::cout << factorial(5) << std::endl; // 输出: 120
return 0;
}
1.3.4 { }:和普通函数一样。
1.4 常用使用例子
与 STL 算法结合(最常用)
#include <iostream>
#include <vector>
#include <algorithm> // for std::for_each, std::sort, etc.
int main() {
std::vector<int> numbers = {3, 1, 4, 1, 5, 9, 2, 6};
// 1. 使用 lambda 进行排序(按降序)
std::sort(numbers.begin(), numbers.end(), [](int a, int b) {
return a > b; // 降序规则
});
// 2. 使用 lambda 打印每个元素(for_each)
std::for_each(numbers.begin(), numbers.end(), [](int n) {
std::cout << n << " ";
});
std::cout << std::endl;
// 3. 使用 lambda 计算有多少个大于 5 的数(count_if)
int count = std::count_if(numbers.begin(), numbers.end(), [](int n) {
return n > 5;
});
std::cout << "Count of numbers > 5: " << count << std::endl;
// 4. 使用 lambda 查找第一个偶数(find_if)
auto it = std::find_if(numbers.begin(), numbers.end(), [](int n) {
return n % 2 == 0;
});
if (it != numbers.end()) {
std::cout << "First even number: " << *it << std::endl;
}
return 0;
}
捕获局部变量
#include <iostream>
#include <vector>
#include <algorithm>
int main() {
std::vector<int> scores = {85, 92, 78, 96, 88};
int passing_score = 90;
// 值捕获 passing_score
auto it = std::find_if(scores.begin(), scores.end(),
[passing_score](int score) { // 将 passing_score 的值拷贝进来
return score >= passing_score;
});
// 引用捕获,用于修改外部变量
int count = 0;
std::for_each(scores.begin(), scores.end(),
[&count](int score) { // 通过引用捕获 count,以便修改它
if (score > 90) count++;
});
std::cout << "Number of scores above 90: " << count << std::endl;
return 0;
}
在异步编程中的应用(如 std::thread, std::async)
#include <iostream>
#include <thread>
#include <future>
int main() {
int x = 10;
// 启动一个线程,lambda 捕获了 x 的引用
std::thread t([&x]() {
std::this_thread::sleep_for(std::chrono::seconds(1));
x *= 2; // 在线程中修改 x
std::cout << "In thread, x = " << x << std::endl;
});
std::cout << "In main, x = " << x << std::endl;
t.join(); // 等待线程结束
std::cout << "After thread, x = " << x << std::endl; // x 已被修改
// 与 std::async 结合,进行异步计算
auto future = std::async(std::launch::async, [](int a, int b) {
return a + b;
}, 20, 30); // 参数 20 和 30 传递给 lambda
int result = future.get(); // 获取异步结果
std::cout << "Async result: " << result << std::endl;
return 0;
}
作为回调函数
#include <iostream>
#include <functional>
// 一个模拟的按钮类
class Button {
public:
// 设置点击事件回调函数
void setOnClick(const std::function<void()>& callback) {
onClick_ = callback;
}
void click() {
if (onClick_) {
onClick_();
}
}
private:
std::function<void()> onClick_;
};
int main() {
Button btn;
std::string message = "Button clicked!";
// 设置 lambda 作为回调,捕获了 message
btn.setOnClick([&message]() {
std::cout << message << std::endl;
});
// 模拟点击事件
btn.click();
return 0;
}
2.std::bind:将可调用对象(函数,函数指针,成员函数,lambda等)与其它参数进行绑定,生成一个新的可调用对象。
1.头文件和语法
#include <functional> // 必须包含这个头文件
auto new_callable = std::bind(existing_callable, arg_list);
2。函数参数
existing_callable:现有的可调用对象。
arg_list:参数列表。可以是占位符(如 std::placeholders::_1, _2, ...),也可以是具体的值
3.举例
绑定普通函数,并固定部分参数
#include <iostream>
#include <functional>
// 一个普通函数
void print_sum(int a, int b, int c) {
std::cout << a << " + " << b << " + " << c << " = " << (a + b + c) << std::endl;
}
int main() {
// 将 print_sum 的第三个参数固定为 100
// _1 和 _2 是占位符,表示新可调用对象的第一和第二个参数
auto bind_func1 = std::bind(print_sum, std::placeholders::_1, std::placeholders::_2, 100);
// 调用 bind_func1(10, 20) 相当于调用 print_sum(10, 20, 100)
bind_func1(10, 20);
// 也可以重新排列参数顺序
// 绑定为:第一个参数固定为 1,第二个参数是调用时的第一个参数,第三个参数是调用时的第二个参数
auto bind_func2 = std::bind(print_sum, 1, std::placeholders::_2, std::placeholders::_1);
// 调用 bind_func2(200, 300) 相当于调用 print_sum(1, 300, 200)
bind_func2(200, 300);
return 0;
}
绑定成员函数(非常重要)
成员函数有一个隐式的 this 指针作为第一个参数。
#include <iostream>
#include <functional>
class Calculator {
public:
int multiply(int a, int b) {
std::cout << "Calculating... ";
return a * b;
}
};
int main() {
Calculator calc;
// 绑定成员函数
// 第一个参数必须是该类的对象(或指针/引用)
// 方式1:使用对象
auto bound_member = std::bind(&Calculator::multiply, calc, // 传入对象,会拷贝一份
std::placeholders::_1,
std::placeholders::_2);
std::cout << bound_member(5, 6) << std::endl;
// 方式2:使用对象引用(更常用,避免不必要的拷贝)
auto bound_member_ref = std::bind(&Calculator::multiply, &calc, // 传入对象指针
std::placeholders::_1,
std::placeholders::_2);
std::cout << bound_member_ref(7, 8) << std::endl;
// 方式3:固定部分参数
auto bound_member_fixed = std::bind(&Calculator::multiply, &calc,
10, // 固定第一个参数为 10
std::placeholders::_1); // 调用时只提供一个参数
std::cout << bound_member_fixed(5) << std::endl; // 相当于 calc.multiply(10, 5)
return 0;
}
绑定 lambda 表达式
既然 std::bind 接受任何可调用对象,自然也可以绑定 lambda。
#include <iostream>
#include <functional>
int main() {
auto my_lambda = [](int a, const std::string& b, double c) {
std::cout << a << ", " << b << ", " << c << std::endl;
};
// 绑定 lambda,并固定第二个和第三个参数
auto bound_lambda = std::bind(my_lambda,
std::placeholders::_1, // 新调用对象的第一个参数对应 lambda 的第一个参数
"Hello", // 固定 lambda 的第二个参数
3.14); // 固定 lambda 的第三个参数
// 调用 bound_lambda(100) 相当于调用 my_lambda(100, "Hello", 3.14)
bound_lambda(100);
return 0;
}

1059

被折叠的 条评论
为什么被折叠?



