使用前,包頭文件:
#include <functional>
std::function
是 C++標準庫 中的一個通用函數包裝器;
它可以儲存、復制、調用任何可調用的對象,包括:函數指針、成員函數、綁定的成員函數、lambda表達式、仿函數等。
1. function 的模板原型
#include <functional>function<Ret(Args...)>
// Ret 是被調用函數的返回值類型
// Args... 是被調用函數的形參
舉一個函數指針的例子講解:
int fun(int a, int b) {return a + b;
}int main() {function<int(int, int)> func1 = fun; // 此處的 fun 本質是 fun() 的函數指針,與 &fun 無差別// <int(, )> : int 為被調用函數的返回值類型// (int, int) : 為被調用函數的形參return 0;
}
2. function 的幾種使用方法
2.1 函數指針
上面的例子已經展示過了。
2.2 成員函數
class Plus
{
public:static int Plusi(int a, int b) // 靜態成員函數{return a + b;}double Plusd(double a, double b) // 非靜態成員函數{return a + b;}
};int main()
{function<int(int, int)> func2 = &Plus::Plusi;cout << func2(1, 1) << endl;// 非靜態成員函數,第一個參數為隱藏的 this 指針function<double(Plus, double, double)> func3 = &Plus::Plusd; cout << func3(Plus(), 1.1, 2.2) << endl;return 0;
}
2.3 lambda 表達式
int main()
{function<int(int, int)> func4 = [](int a, int b) { return a + b; };return 0;
}
2.4 仿函數
struct Fun {int operator()(int a, int b) {return a + b;}
};int main()
{function<int(int, int)> func5 = Fun();return 0;
}
3. 包裝器解決模板效率低下的問題
將下面的代碼運行起來,觀察 useF() 模板被實例化成了幾份?
template<class F, class T>
auto useF(F f, T x) // 實際場景中不建議用 auto 推導返回值類型
{static int count = 0;cout << "count: " << ++count << endl;cout << "count: " << &count << endl;return f(x);
}double f(double x)
{return x / 2;
}struct Fun
{double operator()(double x){return x / 3;}
};int main()
{auto f1 = [](double x) { return x / 4; };cout << useF(f1, 11.11) << endl;cout << useF(f, 11.11) << endl;cout << useF(Fun(), 11.11) << endl;return 0;
}
從運行結果中可以看出, count 始終為 1 且每一個 count 的地址都不相同。事實上,useF() 被實例化成了三份。
我們可以利用包裝器解決模板效率低下的問題。
function<double(double)> func1 = f1;cout << useF(func1, 11.11) << endl << endl;function<double(double)> func2 = f;cout << useF(func2, 11.11) << endl << endl;function<double(double)> func3 = Fun();cout << useF(func2, 11.11) << endl << endl;
為什么通過
std::function
包裝后,useF() 只會實例化出一份呢?不妨通過
typeid
觀察 func1、func2、func3 的類型。