這兩天在看c++ STL模板庫,被函數適配器折磨得死去活來的,查閱了很多資料,終於有點小小的見解。
我們現在想做的事情是找出vector中大於5的數的個數,我們當然會立刻想到用for循環來寫,比如下面的方式
for(std::vector<int>::iterator ite = vec.begin(), ite != vec.end(), ++ ite)
{
if(5< *ite)
++count;
}
這樣做是正確的,但是當我們學了泛型算法,我們就會找到更爲合適的方法來達到這個目的,並且能保證正確性和簡潔性,比如
count_if,count_if需要傳入一個函數對象,但問題在於我們還要傳入一參數5,讓容器的所有數都和5做比較,這個時候函數對象適
配器就隆重登場了,讓我們來看看,它是怎麼工作得。
首先我將STL中的binder1st的源碼中最重要的部分擺出來,稍微做一些修改,注意完全是爲了我們好理解。
binder1st:
template<class T>class binder1st:public unary_function<typename T::second_argument_type,typename T::result_type>
{
//最核心代碼,我們需要理解的部分
binder1st(const T& X, const typename T::first_argument_type& Y):
op(X),value(Y){} //構造函數將X作爲運算符,然後傳入一個綁定爲常量的值
result_type operator() ( const argument_type& X) const{
return (op(value,X));
private:
T op; //運算符
typename T::first_argument_type value; //常量值
}
}
binder1st一般不怎麼使用,在程序中一般使用bind1st,bind1st調用了binder1st類。我們來做一下測試。
int main()
{
//聲明一個數組
int a[] = {1,2,3,4,5,6,7,8};
const int N = sizeof(a)/sizeof(int);
std::vector<int> vec(a,a+N);
int vcount = std::count_if(vec.begin(),vec.end(),std::bind1st(std::less<int>(),5));
std::cout<<vcount<<std::endl;
return 0;
}
我們對上面的程序調用做一下說明,調用bind1st(std::less<int>(),5),將less<int>()這個操作符傳入到binder1st的構造函數中去,相當
於OP現在代表的是less<int>(),而binder1st::value = 5,在後面的算法中就會調用op(value,X)less(5,*iter),就相當於是每一次比較是否有
5<*iter,如果結果爲真,則返回true,否則返回false。同理binder2nd的實現原理和binder1st類似,不過不同在於在後面執行op操作
的時候是採用op(X,value),那上面的程序用binder2nd可以修改如下:
int main()
{
//聲明一個數組
int a[] = {1,2,3,4,5,6,7,8};
const int N = sizeof(a)/sizeof(int);
std::vector<int> vec(a,a+N);
int vcount = std::count_if(vec.begin(),vec.end(),std::bind2nd(std::greater<int>(),5));
std::cout<<vcount<<std::endl;
return 0;
}
輸出的結果都是3