標籤:turn vector 需要 code second src 自己 main alt
仿函數(functors)其實就是重載了operator()的對象。
下面簡單先看看它的一個例子:
1 #include <iostream> 2 using namespace std; 3 4 template<typename T> 5 struct m_plus 6 { 7 T operator()(const T& x, const T& y) { return x + y; } 8 }; 9 10 int main(int argc, char *argv[])11 {12 // 定義其對象 調用其operator()13 m_plus<int> op;14 cout << op(1, 2) << endl;15 // 產生一個匿名對象 這是仿函數的主流用法16 cout << m_plus<int>()(1, 2) << endl;17 return 0;18 }View Code
既然仿函數跟函數的用法類同,那為什麼不直接使用函數指標代替呢?
個人認為有兩個原因
1.仿函數可以有自己的狀態,而函數指標則不行(有的使用template或者static變數可以實現)。
我們可以這樣子使用仿函數:
1 #include <iostream> 2 using namespace std; 3 4 template<typename T, T add> 5 struct m_plus 6 { 7 m_plus() { _add = add; } 8 T operator()(const T& x) { return x + _add; } 9 // 仿函數可以具有自己的狀態10 int _add;11 };12 13 int main(int argc, char *argv[])14 {15 m_plus<int, 10> op;16 cout << op(100) << endl;17 cout << op(200) << endl;18 return 0;19 }View Code
2.仿函數可以與函數適配器搭配使用。
舉一個例子,例如我們如果要使用count_if演算法來計算容器中大於10的元素的個數。
如果我們使用greater<int>作為判別式(二元),而count_if只接受一個一元判別式,這時候我們就需要搭配函數適配器一起使用了。
而函數指標不能搭配函數適配器一起使用,具體在分析bind2nd的時候會講到。
1 #include <iostream> 2 #include <vector> 3 #include <functional> 4 #include <algorithm> 5 using namespace std; 6 7 8 int main(int argc, char *argv[]) 9 {10 vector<int> coll{ 1, 3, 5, 7, 9, 11, 13, 15 };11 // 接著下面有bind2nd的具體實現12 cout << count_if(coll.begin(), coll.end(), bind2nd(greater<int>(), 10)) << endl;13 return 0;14 }View Code
bind2nd
bind2nd可以將二元仿函數轉化為一元仿函數,這看上去好像很神奇,其實它的實現很簡單。
首先,二元仿函數會繼承自binary_function,其實只是一些typedef,這些都將用於函數適配器。
1 template <class Arg1, class Arg2, class Result> 2 struct binary_function { 3 typedef Arg1 first_argument_type; 4 typedef Arg2 second_argument_type; 5 typedef Result result_type; 6 }; 7 8 template <class T> 9 struct greater : public binary_function<T, T, bool> {10 bool operator()(const T& x, const T& y) const { return x > y; }11 };View Code
bind2nd將二元仿函數跟第二個參數型別作為模板型別,下面是具體實現:
1 template <class Operation, class T> 2 inline binder2nd<Operation> bind2nd(const Operation& op, const T& x) { 3 typedef typename Operation::second_argument_type arg2_type; 4 // 調用binder2nd 5 return binder2nd<Operation>(op, arg2_type(x)); 6 } 7 8 // binder2nd是一個一元仿函數(本身可以搭配函數適配器一起使用) 9 template <class Operation> 10 class binder2nd11 : public unary_function<typename Operation::first_argument_type,12 typename Operation::result_type> 13 {14 protected:15 // 傳進來的二元仿函數16 Operation op;17 // 傳進來的第二個參數 因為仿函數內部可以typedef 而函數指標則不行18 // 因此只能適配仿函數 而不能適配函數指標19 typename Operation::second_argument_type value;20 public:21 // 建構函式22 binder2nd(const Operation& x,23 const typename Operation::second_argument_type& y) 24 : op(x), value(y) {}25 26 // 直接調用二元仿函數 27 typename Operation::result_type28 operator()(const typename Operation::first_argument_type& x) const {29 return op(x, value); 30 }31 };View Code
STL源碼剖析(仿函數/bind2nd)