find(),find_if(),以及巧妙的函數對象,函數適配器


在學習到《Essential C++》3.6節時自己按照自己的想法來實現書上提到的思路。代碼雖然簡單,不過自己卻發現有很多其他地方不熟悉,比如函數指針的用法,仿函數和函數適配器的使用。搗鼓了半天,總算懂了點眉目,簡單總結下以備忘。

文檔按照五部分分寫,先依次簡單地介紹find()與find_if()算法、函數指針用法、仿函數(functon object)和函數適配器(function adapters)。最后貼上自己實驗的代碼並簡單分析。

一、
因為問題起於泛型搜索算法find_if(),所以先總結下有關find()和find_if()。 聲明:
        InputIterator
        find (InputIterator beg, InputIterator end, const T& value)
        InputIterator
        find_if(InputIterator beg, InputIterator end, UnaryPredicate op)第一種形式返回在搜索域[beg,end)內與value值相等的元素的地址;
第二種形式返回在搜索域[beg,end)內滿足一元謂詞函數op(elem)為真的元素的地址。
     1) 以上兩種形式在搜索不到匹配元素的情況下均返回end;
     2) 注意op函數調用期間不能夠改變自身的狀態;
     3) op不能更改傳遞進來的參數;

二、
為了增強泛型算法的靈活性,一些泛型算法允許傳遞用戶自定的的函數。泛型算法在使用輔助函數時有不同的方式,有些是可以省略的,即算法是可以不用給定的函數,而有些是強制性的,即必須使用這些函數。如下         
// CODE SNIPPET
        void print (int elem)
        {         
                cout <<elem <<’ ‘;
        }
        ……
        for_each (coll.begin(), coll.end(), print);一種特殊的輔助函數便是謂詞函數,謂詞函數通常指的是返回值為boolean的函數,它們通常用來為排序或者搜索算法指定參照條件。在使用中謂詞函數可分為帶有一個參數的謂詞函數(unary)和需要兩個參數的謂詞函數(binary),值得注意的是並不是所有返回值為boolean類型的函數都是合法的謂詞函數。

三、
仿函數是一種對象,但它具有函數一樣的功能,並且比函數更有優勢。其中一點便是效率更高。我們使用的仿函數通常被聲明為inline,所以其大部分執行邏輯在編譯時已經基本確定,因而少掉了頻繁調用函數的開銷。可以自己定義簡單的仿函數,如下: // CODE SNIPPET
class Print{
        public:
                void operator() (int elem) const
                {
                        cout <<elem <<’ ‘;
                 }
};
……
for_each (coll.begin(), coll.end(), Print());
……C++的STL中提供了多種預定義的仿函數,如negate<type>(), plus<type>(), minus<type>(), multiplies<type>(), divides<type>(), modulus<type>(), equal_to<type>(), not_equal_to<type>(), less<type>(), greater<type>(), less_equal<type>(), greater_equal<type>(), logical_not<type>(), logical_and<type>(), logical_or<type>().

四、
函數適配器也是一種仿函數,不過這種仿函數更為高等,因為它可以將一個仿函數與另一個仿函數/ 值/ 特殊的函數結合起來。

不難發現,STL常使用的仿函數雖然提供了多種有用的仿函數,然而這些仿函數均是通過迭代器對容器里面的元素進行操作,但是有時候你還需要用其他的值結合,這時候便可以使用函數適配器(見下面的例子)。


編譯不能通過的代碼如下所示: // code snippet
#include <iostream>
#include <vector>
#include <algorithm>
#include <functional>

using namespace std;

bool less_than(int a, int b)
{
        return (a<b ? true:false);
}

vector<int> filter(const vector<int> &vec, int filter_value, bool (*ptr_func)(int, int))
{
        vector<int> temp;
        vector<int>::const_iterator iter = vec.begin();

        while (find_if(iter, vec.end(), ptr_func(*iter, filter_value)) != vec.end())
        {
                temp.push_back(*iter);
                ++iter;
        }        
        return temp;
}

void display(vector<int> &vec)
{
        for (int ix=0; ix<vec.size(); ++ix)
                cout <<vec[ix] <<" ";
        cout <<"\n";
}
        
int main()
{
        const int nsize = 5;
        int int_arr[nsize] = { 2, 4, 5, 6, 7};
        vector<int>vec(int_arr, int_arr+nsize);
        display(vec);
        vector<int>result;

        result = filter(vec, 6, less_than);
        display(result);
        
        return 0;        
}可見,我在使用find_if()函數的時候,將里面本應該為“函數指針”的第三個參數寫成了對這個函數的“函數調用”,這是不允許的。但整個程序的思路並沒有錯,因為上面的代碼可以通過仿函數來解決的。

上面也提到,一般通用的仿函數僅是對容器里面的值進行處理,但本例的思路是需要將容器里面的每個值以此與另一個值val進行比較的。所以必須要使用到函數適配器來將一個仿函數與一個值進行綁定。如下是更正后的代碼: // code snippet
#include <iostream>
#include <vector>
#include <algorithm>
#include <functional>

using namespace std;

bool less_than(int a, int b)
{
        return (a<b ? true:false);
}

vector<int> filter(const vector<int> &vec, int val, less<int>&lt)
{
        vector<int> nvec;
        vector<int>::const_iterator iter = vec.begin();
        
        while ((iter=find_if(iter, vec.end(), bind2nd(lt, val))) != vec.end())
        {
                nvec.push_back(*iter);
                iter ++;
        }
        return nvec;
}

void display(vector<int> &vec)
{
        for (int ix=0; ix<vec.size(); ++ix)
                cout <<vec[ix] <<" ";
        cout <<"\n";
}
        
int main()
{
        const int nsize = 5;
        int int_arr[nsize] = { 2, 4, 5, 6, 7};
        vector<int>vec(int_arr, int_arr+nsize);
        display(vec);
        vector<int>result;

        result = filter(vec, 6, less<int>());
        display(result);
        
        return 0;        
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM