函式指標是 C 語言回調基石;函式物件 (Functor) 是 C++ 泛型程式設計核心。本文系統對比兩者語法、效能、表達力,並展示 STL 如何以函式物件實現高效演算法。
// 普通函式宣告
int func(int x);
// 函式指標宣告:括號關鍵
int (*pf)(int x);
// typedef 簡化
typedef int (*PF)(int x);
PF pf;
void bar(char ch, int i) { std::cout << "bar " << ch << ' ' << i << "\n"; }
typedef void (*PFT)(char, int);
PFT pft = bar; // 指向 bar
pft('e', 91); // 呼叫:bar e 91
(*pft)('e', 91); // 等價寫法
void foo(char ch, int i, PFT pf) {
pf(ch, i); // 呼叫傳入的函式
}
foo('e', 12, pft); // 靈活切換行為
std::mem_fn 或 Lambda)operator() 的類別
struct Adder {
int operator()(int a, int b) const {
std::cout << a << '+' << b << '=' << a+b << "\n";
return a;
}
};
Adder add;
add(1, 3); // 像函式呼叫:1+3=4
int addFunc(int a, int b, Adder& func) {
return func(a, b);
}
struct GenericAdder {
template
T operator()(T a, T b) const {
std::cout << a << '+' << b << '=' << a+b << "\n";
return a;
}
};
template
T addFuncT(T a, T b, Func& f) { return f(a, b); }
GenericAdder gadd;
addFuncT(2, 4, gadd); // int
addFuncT(1.4, 2.3, gadd); // double
| 維度 | 函式指標 | 函式物件 |
|---|---|---|
| 狀態 | 無狀態 | 可攜帶狀態 (成員變數) |
| 內聯最佳化 | 困難 (間接呼叫) | 容易 (編譯器可內聯 operator()) |
| 型別安全 | 簽名匹配即可 | 模板參數推導強型別 |
| 成員函式綁定 | 需 std::mem_fn | Lambda 捕獲 this 即可 |
| STL 相容性 | 可用但受限 | 標準要求 (仿函數概念) |
#include
#include
#include
std::vector v = {5, 2, 8, 1, 9};
// 1. 標準仿函數
std::sort(v.begin(), v.end(), std::greater()); // 降序
// 2. Lambda (C++11) - 最現代寫法
std::sort(v.begin(), v.end(), [](int a, int b){ return a > b; });
// 3. 狀態仿函數:計算大於閾值的個數
struct GreaterThan {
int threshold;
GreaterThan(int t) : threshold(t) {}
bool operator()(int x) const { return x > threshold; }
};
int count = std::count_if(v.begin(), v.end(), GreaterThan(5)); // 攜帶狀態
std::function。std::function<Sig> (型別擦除,略有開銷)。std::function 型別擦除成本。(+[](int x){return x;})。
#include
// 判斷是否為可呼叫物件
template
using is_callable = std::is_invocable;
// C++20 concepts
template F>
void call_with_int(F f) { f(42); }
函式指標是「指向程式碼的指標」;函式物件是「可呼叫的物件」。後者以狀態封裝、內聯最佳化、型別豐富三大優勢,成為 C++ 泛型程式設計 (STL、Boost、現代標準庫) 的基石。掌握從函式指標 → 仿函數 → Lambda → Concepts 的演進脈絡,是精通現代 C++ 的關鍵里程碑。