提到C++ STL,首先被人想到的是它的三大組件:Containers, Iterators, Algorithms,即容器,迭代器和算法。容器為用戶提供了常用的數據結構,算法大多是獨立於容器的常用的基本算法,迭代器是由容器提供的一種接口,算法通過迭代器來操控容器。接下來要介紹的是另外的一種組件,函數對象(Function Object,JJHou譯作Functor仿函數)。
什么是函數對象
顧名思義,函數對象首先是一個對象,即某個類的實例。其次,函數對象的行為和函數一致,即是說可以像調用函數一樣來使用函數對象,如參數傳遞、返回值等。這種行為是通過重載類的()操作符來實現的,舉例說明之,
class Print
{ public: void operator()(int n) { std::cout<<n<<std::endl; return ; } }; int main(int argc, char **argv) { Print print; print(372); print.operator()(372); //~ 顯式調用 return 0; } |
其實我們早就開始使用函數對象了,當你寫下sort(v.begin(), v.end())時(假定v是vector<int>),其實調用的是sort(v.begin(), v.end(), less<int>()),這樣sort就會將v從小至大排序。若要逆向排序,你就需要顯式地為sort指定一個排序規則,即函數對象greater<int>(). less<T>和greater<T>是STL中的兩個模板類,它們使用類型T的<和>操作符。less<T>的一個典型實現可能是這樣的:
template <class T> class less { public: bool operator()(const T&l, const T&r)const { return l < r; } }; |
函數對象的分類
根據用途和參數特征,STL中的函數對象通常分為以下幾類:Predicates, Arithmetic Function Objects, Binders, Negaters, Member Function Adapters, Pointer to Function Adapters。下面逐一介紹一下,之前得先介紹兩個基類:
template<class Arg, class Res> struct unary_function //~ 一元函數對象基類 { typedef Arg argument_type; typedef Res result_type; }; template<class Arg1, class Arg2, class Res> struct binary_function //~ 二元函數對象基類 { typedef Arg1 first_argument_type; typedef Arg2 second_argument_type; typedef Res result_type; }; |
使用這兩個基類,首先需要包含頭文件。
Predicates
Predicate是一種函數對象,返回值(應該是operator()的返回值)為布爾型,接受一個或者兩個參數。通常用來判斷對象的有效性(一個參數時)或者對兩個對象進行比較(如less)。你可以根據自己的需要定義自己的Predicate,但STL已經定義了一些Predicate,你可以直接使用。
Predicate | 類型 | 描述 |
---|---|---|
equal_to() | Binary | 使用==判等 |
not_equal_to() | Binary | 使用!=判等 |
less() | Binary | 使用< |
greater() | Binary | 使用> |
less_equal() | Binary | 使用<= |
greater_equal() | Binary | 使用>= |
logical_not() | Unary | 使用!邏輯取反 |
logical_and() | Binary | 使用&&邏輯與 |
logical_or() | Binary | 使用||邏輯或 |
算術運算函數對象
進行簡單的算術運算,這類函數對象我用的很少,通常是自己定義。
函數對象 | 類型 | 描述 |
---|---|---|
negate() | Unary | 使用-求負 |
plus() | Binary | 使用+加法 |
minus() | Binary | 使用-減法 |
multiplies() | Binary | 使用*乘法 |
divides() | Binary | 使用/除法 |
modulus() | Binary | 使用%求余 |
綁定Binders
有兩種綁定bind1st和bind2nd,它們可以將一個二元函數對象的其中一個參數綁定為某個已知的對象,從而得到一個一元函數對象。例如要在vector<int> v中查找等於372的值的位置,我可以將372綁定到equal_to<int>()的第一個或者第二個參數:
int
main(int argc, char **argv) { vector<int> v; for(int i = 0; i < 1000; ++i) { v.push_back(i); } vector<int>::iterator it; it = find_if(v.begin(), v.end(), bind1st(equal_to<int>(), 372)); std::cout<<*it<<std::endl; return 0; } |
其實,這里的bind1st和bind2nd並不是函數對象,只是模板函數而已。這兩個函數分別返回類型為binder1st和binder2nd的函數對象。下面的代碼,聰明的你肯定一看就懂:
// bind1st
template<class Op> class binder1st : public unary_function <typename Op::second_argument_type, typename Op::result_type> { Op op_; typename Op::first_argument_type first_arg_; public: binder1st(const Op& op, const typename Op::first_argument_type& first_arg) : op_(op), first_arg_(first_arg) {} typename Op::result_type operator() (const typename Op::second_argument_type& arg) const { return op_(first_arg_, arg); } }; template<class Op, class Arg> inline binder1st<Op> bind1st(const Op& op, const Arg& arg) { return binder1st<Op>(op, arg); } // bind2nd template<class Op> class binder2nd : public unary_function <typename Op::first_argument_type, typename Op::result_type> { Op op_; typename Op::second_argument_type second_arg_; public: binder2nd(const Op& op, const typename Op::second_argument_type& second_arg) : op_(op), second_arg_(second_arg) {} typename Op::result_type operator()(const typename Op::argument_type& arg) const { return op_(arg, second_arg_); } }; template<class Op, class Arg> inline binder2nd<Op> bind2nd(const Op& op, const Arg& arg) { return binder2nd<Op>(op, arg); } |
Negaters
Negater是針對Predicate設計的,它簡單的將Predicate的返回值取反。有兩個Negater,not1和not2,分別對一元和二元Predicate取反。
Member Function Adapters
有時候,你可能想讓算法調用容器元素的成員函數,而不是外部函數。因為外部無法改變對象內的狀態,且內部函數通常具有更高的效率。例如swap(string, string)總是沒有string.swap(string)快速。又比如sort無法對list進行排序,這時候只能使用list.sort()來給鏈表排序。這時候就需要使用一定的方法將對象內部的函數“變成”函數對象,這樣的函數對象叫做成員函數適配器,其實前面的binder也是一種適配器。看下面的例子:
int
main(int argc, char **argv) { vector<list<int> > v; v.push_back(list<int>()); vector<list<int> >::iterator it; for(it = v.begin(); it != v.end(); ++it) { for(int i = 0; i < 20; ++i) { (*it).insert((*it).begin(), i); } } for_each(v.begin(), v.end(), std::mem_fun_ref(&list<int>::sort)); for(it = v.begin(); it != v.end(); ++it) { for(list<int>::iterator lt; lt != (*it).end(); ++lt) { std::cout<<*lt<<std::endl; } } return 0; } |
上面的例子中,遍歷vector<list<int> >並對鏈表進行排序。其中使用的是成員函數適配器mem_fun_ref,它返回的函數對象會以list<int>對象的引用為參數。另外一個mem_fun則是以指向list<int>對象的指針為參數。
from:http://www.cnblogs.com/weiqubo/archive/2011/02/16/1956552.html