std::function 是可調用對象的類型擦除包裝器,支持函數指針、仿函數、Lambda、std::bind 綁定結果等。
#include <functional>
#include <iostream>
using cb1_t = std::function<void()>;
using cb2_t = std::function<void(int)>;
void foo1() { std::cout << "foo1 called\n"; }
void foo2(int i) { std::cout << "foo2 called with: " << i << "\n"; }
struct S { void foo3() { std::cout << "foo3 called.\n"; } };
int main() {
// 綁定自由函數
cb1_t f1 = std::bind(&foo1); f1();
// 綁定帶參數函數(參數綁定)
cb1_t f2 = std::bind(&foo2, 5); f2();
// 綁定佔位符(參數延遲綁定)
cb2_t f3 = std::bind(&foo2, std::placeholders::_1); f3(42);
// 綁定成員函數
S s; cb1_t f4 = std::bind(&S::foo3, &s); f4();
// 綁定 Lambda
cb1_t f5 = std::bind([] { std::cout << "lambda called\n"; }); f5();
return 0;
}
std::vector<std::function<void()>> 可存儲同簽名回調。異構簽名需用 std::variant (C++17) 或類型擦除基類。
using cb1_t = std::function<void()>;
using callbacks_t = std::vector<cb1_t>;
callbacks_t callbacks;
void foo1() { std::cout << "foo1\n"; }
void foo2(int i) { std::cout << "foo2: " << i << "\n"; }
int main() {
callbacks.push_back(std::bind(&foo1));
callbacks.push_back(std::bind(&foo2, 5)); // 參數靜態綁定
int n = 15;
callbacks.push_back(std::bind(&foo2, std::cref(n))); // 參數運行時綁定
for (auto& f : callbacks) f();
return 0;
}
將任意可調用對象包裝為 std::function 作為函數參數,統一接口。提供多重重載支持:
std::function 直接調用std::function 再調用std::function 開銷
#include <functional>
#include <iostream>
using cb1_t = std::function<void()>;
using cb2_t = std::function<void(int)>;
// 1. 包裝 std::function 無參
template<typename R> void call(std::function<R()> f) { f(); }
// 2. 包裝 std::function 有參
template<typename R, typename... Args> void call(std::function<R(Args...)> f, Args... args) { f(args...); }
// 3. 通用可調用對象無參 → 委托給 1
template<typename R> void call(R (*f)()) { call(std::function<R()>(f)); }
// 4. 通用可調用對象有參 → 委托給 2
template<typename R, typename... Args> void call(R (*f)(Args...), Args... args) { call(std::function<R(Args...)>(f), args...); }
// 5. 函數指針專用(避免 std::function 開銷)
using fp = void(*)();
void call(fp f) { call(std::function<void()>(f)); }
void foo1() { std::cout << "foo1\n"; }
void foo2(int i) { std::cout << "foo2: " << i << "\n"; }
int main() {
call(&foo1);
cb1_t f1 = std::bind(&foo1); call(f1);
call(&foo2, 5);
cb2_t f2 = std::bind(&foo2, std::placeholders::_1); call(f2, 5);
call([] { std::cout << "lambda\n"; }); // 調用 fp 重載
return 0;
}
std::function 有類型擦除開銷(堆分配、虛函數調用),熱路徑優先用模板/函數指針std::bind 比 Lambda 稍慢,現代 C++ 推薦 Lambda + std::function 僅在必要時使用vector<function<Sig>>variant<function<Sig1>, function<Sig2>...> 或基類類型擦除std::function 支持移動,避免拷貝開銷