std::functional 使用场景
作者:互联网
2026-03-05
std::functional 是 C++ 标准库中一个非常强大的工具,它提供了一种**类型擦除(type erasure)**机制,让你能够存储、传递和调用任何可调用对象(callable)。
核心作用
1. 统一的可调用对象包装器
std::function 可以包装任何可调用实体,只要签名匹配:
- 普通函数
- Lambda 表达式
- 函数对象(仿函数)
- 成员函数(通过
std::bind或 lambda) - 甚至其他
std::function
2. 类型擦除
隐藏具体类型,只暴露接口。这使得你可以:
- 在容器中存储不同类型的可调用对象
- 作为函数参数接受任意可调用对象
- 实现回调机制而不需要模板
主要使用场景
场景 1:回调函数(Callbacks)
#include
#include
class Button {
std::function<void()> onClick_;
public:
void setOnClick(std::function<void()> callback) {
onClick_ = callback;
}
void click() { if (onClick_) onClick_(); }
};
// 使用
Button btn;
btn.setOnClick([]() { std::cout << "Clicked!n"; });
btn.click();
场景 2:策略模式 / 算法注入
#include
#include
#include
void processData(std::vector<int>& data,
std::function<bool(int)> filter,
std::function<int(int)> transform) {
// 先过滤
data.erase(std::remove_if(data.begin(), data.end(),
[&](int x) { return !filter(x); }), data.end());
// 再转换
for (auto& x : data) x = transform(x);
}
// 使用
std::vector<int> nums = {1, 2, 3, 4, 5, 6};
processData(nums,
[](int x) { return x % 2 == 0; }, // 只保留偶数
[](int x) { return x * x; } // 平方
);
场景 3:事件系统 / 观察者模式
#include
#include
#include
class EventSystem {
std::vectorvoid(const std::string&)>> listeners_;
public:
void subscribe(std::function<void(const std::string&)> listener) {
listeners_.push_back(listener);
}
void emit(const std::string& event) {
for (auto& listener : listeners_) {
listener(event);
}
}
};
// 使用
EventSystem events;
events.subscribe([](const std::string& e) {
std::cout << "Logger: " << e << "n";
});
events.subscribe([](const std::string& e) {
std::cout << "Metrics: recorded " << e << "n";
});
场景 4:延迟执行 / 任务队列
#include
#include
#include
class TaskQueue {
std::queuevoid()>> tasks_;
public:
void addTask(std::function<void()> task) {
tasks_.push(task);
}
void runAll() {
while (!tasks_.empty()) {
tasks_.front()();
tasks_.pop();
}
}
};
// 使用
TaskQueue queue;
queue.addTask([]() { std::cout << "Task 1n"; });
queue.addTask([]() { std::cout << "Task 2n"; });
queue.runAll();
场景 5:绑定成员函数
#include
#include
class Calculator {
public:
int add(int a, int b) { return a + b; }
int multiply(int a, int b) { return a * b; }
};
// 使用 std::bind
Calculator calc;
auto addFunc = std::bind(&Calculator::add, &calc,
std::placeholders::_1, std::placeholders::_2);
std::cout << addFunc(3, 4); // 7
// 或者使用 lambda(更推荐,性能更好)
auto multiplyFunc = [&calc](int a, int b) {
return calc.multiply(a, b);
};
std::function vs 模板 vs 裸函数指针
| 特性 | std::function | 模板 | 裸函数指针 |
|---|---|---|---|
| 类型擦除 | 是 | 否 | 是(但只能指向函数) |
| 存储 Lambda | 可以 | 可以 | 不行(除非无捕获) |
| 运行时开销 | 有(虚函数调用) | 无 | 无 |
| 编译时类型检查 | 弱(运行时可能抛 bad_function_call) | 强 | 强 |
| 存储在容器中 | 容易 | 难(需要类型擦除) | 可以 |
最佳实践
-
优先使用模板:如果不需要存储可调用对象,用模板参数更高效
// 更好:零开销 template<typename Func> void execute(Func&& f) { f(); } // 有开销:类型擦除 void execute(std::function<void()> f) { f(); } -
检查空状态:调用前确保
std::function不为空if (func) func(); // 或 if (func != nullptr) -
注意开销:
std::function通常使用小对象优化(SOO),但大对象会堆分配 -
C++23 替代:考虑使用
std::move_only_function(仅移动)或std::copyable_function
std::functional 的核心价值在于灵活性——当你需要在运行时决定调用什么、或者需要在容器中存储可调用对象时,它是不可或缺的工具。
相关推荐
专题
+ 收藏
+ 收藏
+ 收藏
+ 收藏
+ 收藏
最新数据
相关文章
指针、引用和常量的关系
03/26
C++学习笔记(33):智能指针(工厂函数)
03/25
学而时习之:C++中的标准模板5.2
03/25
学而时习之:C++中的预处理
03/23
C++ RAII:从“人肉记账”到“自动保姆”的资源管理革命
03/23
告别 C 风格枚举:为什么你应该使用 enum class
03/22
从智能指针窥见现代C++的生存法则:告别内存泄漏,这篇就够了
03/22
C++学习笔记(30):智能指针(unique_ptr)
03/22
Leetcode第一题:用C++解决两数之和问题
03/20
static 关键字:从 C 到 C++,一篇文章彻底搞懂它的“七十二变”
03/20
AI精选
