C++中std::functional 使用場景
std::functional 是 C++ 標準庫中一個非常強大的工具,它提供了一種**類型擦除(type erasure)**機制,讓你能夠存儲、傳遞和調(diào)用任何可調(diào)用對象(callable)。
核心作用
1.統(tǒng)一的可調(diào)用對象包裝器
std::function 可以包裝任何可調(diào)用實體,只要簽名匹配:
- 普通函數(shù)
- Lambda 表達式
- 函數(shù)對象(仿函數(shù))
- 成員函數(shù)(通過
std::bind或 lambda) - 甚至其他
std::function
2.類型擦除
隱藏具體類型,只暴露接口。這使得你可以:
- 在容器中存儲不同類型的可調(diào)用對象
- 作為函數(shù)參數(shù)接受任意可調(diào)用對象
- 實現(xiàn)回調(diào)機制而不需要模板
主要使用場景
場景 1:回調(diào)函數(shù)(Callbacks)
#include <functional>
#include <iostream>
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 <functional>
#include <vector>
#include <algorithm>
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());
// 再轉(zhuǎn)換
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; }, // 只保留偶數(shù)
[](int x) { return x * x; } // 平方
);
場景 3:事件系統(tǒng) / 觀察者模式
#include <functional>
#include <vector>
#include <string>
class EventSystem {
std::vector<std::function<void(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:延遲執(zhí)行 / 任務(wù)隊列
#include <functional>
#include <queue>
#include <iostream>
class TaskQueue {
std::queue<std::function<void()>> 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 1\n"; });
queue.addTask([]() { std::cout << "Task 2\n"; });
queue.runAll();
場景 5:綁定成員函數(shù)
#include <functional>
#include <iostream>
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::functionvs 模板 vs 裸函數(shù)指針
| 特性 | std::function | 模板 | 裸函數(shù)指針 |
|---|---|---|---|
| 類型擦除 | ? 是 | ? 否 | ? 是(但只能指向函數(shù)) |
| 存儲 Lambda | ? 可以 | ? 可以 | ? 不行(除非無捕獲) |
| 運行時開銷 | 有(虛函數(shù)調(diào)用) | 無 | 無 |
| 編譯時類型檢查 | 弱(運行時可能拋 bad_function_call) | 強 | 強 |
| 存儲在容器中 | ? 容易 | ? 難(需要類型擦除) | ? 可以 |
最佳實踐
優(yōu)先使用模板:如果不需要存儲可調(diào)用對象,用模板參數(shù)更高效
// 更好:零開銷 template<typename Func> void execute(Func&& f) { f(); } // 有開銷:類型擦除 void execute(std::function<void()> f) { f(); }檢查空狀態(tài):調(diào)用前確保
std::function不為空if (func) func(); // 或 if (func != nullptr)
注意開銷:
std::function通常使用小對象優(yōu)化(SOO),但大對象會堆分配C++23 替代:考慮使用
std::move_only_function(僅移動)或std::copyable_function
std::functional 的核心價值在于靈活性——當你需要在運行時決定調(diào)用什么、或者需要在容器中存儲可調(diào)用對象時,它是不可或缺的工具。
到此這篇關(guān)于C++中std::functional 使用場景的文章就介紹到這了,更多相關(guān)C++ std::functional 使用內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
一文帶你學(xué)習(xí)C/C++中的<Windows.h>庫
c語言 #include<windows.h>是寫window程序需要的重要頭文件,下面這篇文章主要給大家介紹了C/C++中<Windows.h>庫的相關(guān)資料,文中通過實例代碼介紹的非常詳細,需要的朋友可以參考下2023-01-01
C++ 基礎(chǔ)編程之十進制轉(zhuǎn)換為任意進制及操作符重載
這篇文章主要介紹了C++ 基礎(chǔ)編程之十進制轉(zhuǎn)換為任意進制及操作符重載的相關(guān)資料,需要的朋友可以參考下2017-02-02
C語言實現(xiàn)簡單的學(xué)生學(xué)籍管理系統(tǒng)
這篇文章主要為大家詳細介紹了C語言實現(xiàn)簡單的學(xué)生學(xué)籍管理系統(tǒng),文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2022-07-07

