初接觸仿函數

來源:互聯網
上載者:User

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

文檔按照五部分分寫,先依次簡單地介紹find()與find_if()演算法、提及函數作為參數的用法(我犯錯了,這裡。)、仿函數(functon object)和函數適配器(function adapters)。最後貼上自己實驗的代碼並簡單分析指出錯誤。

一、
因為問題起於泛型搜尋演算法find_if(),所以先總結下有關find()和find_if()。

Code:
  1. 聲明:   
  2.  InputIterator   
  3.  find (InputIterator beg, InputIterator end, const T& value)   
  4.   
  5.  InputIterator   
  6.  find_if(InputIterator beg, InputIterator end, UnaryPredicate op)   

第一種形式返回在搜尋域[beg,end)內與value值相等的元素的地址;
第二種形式返回在搜尋域[beg,end)內滿足一元謂詞函數op(elem)為真的元素的地址。
? 1)以上兩種形式在搜尋不到匹配元素的情況下均返回end;
? 2)注意op函數調用期間不能夠改變自身的狀態;
? 3)op不能更改傳遞進來的參數;

二、
為了增強泛型演算法的靈活性,一些泛型演算法允許傳遞使用者自定的的函數。泛型演算法在使用輔助函數時有不同的方式,有些是可以省略的,即演算法是可以不用給定的函數,而有些是強制性的,即必須使用這些函數。如下 

Code:
  1. // CODE SNIPPET   
  2.  void print (int elem)   
  3.  {     
  4.   cout <<elem <<’ ‘;   
  5.  }   
  6.  ……   
  7.  for_each (coll.begin(), coll.end(), print);   

注意如上for_each語句中的第三個參數,這個參數接受一個函數指標,此時傳遞的便是函數print()的地址(和數組類似,其名也可指示其地址)。注意,此時不要用print(elem).

一種特殊的輔助函數便是謂詞函數,謂詞函數通常指的是傳回值為boolean的函數,它們通常用來為排序或者搜尋演算法指定參照條件。在使用中謂詞函數可分為帶有一個參數的謂詞函數(unary)和需要兩個參數的謂詞函數(binary),值得注意的是並不是所有傳回值為boolean類型的函數都是合法的謂詞函數。

三、
仿函數是一種對象,但它具有函數一樣的功能,並且比函數更有優勢。其中一點便是效率更高。我們使用的仿函數通常被聲明為inline,所以其大部分執行邏輯在編譯時間已經基本確定,因而少掉了頻繁調用函數的開銷。

可以自己定義簡單的仿函數,如下:

Code:
  1. // CODE SNIPPET   
  2. class Print{   
  3.  public:   
  4.   void operator() (int elem) const  
  5.   {   
  6.    cout <<elem <<’ ‘;   
  7.    }   
  8. };   
  9. ……   
  10. for_each (coll.begin(), coll.end(), Print());   
  11. ……  

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:
  1. // code snippet   
  2. #include <iostream>   
  3. #include <vector>   
  4. #include <algorithm>   
  5. #include <functional>   
  6.   
  7. using namespace std;   
  8.   
  9. bool less_than(int a, int b)   
  10. {   
  11.  return (a<b ? true:false);   
  12. }   
  13.   
  14. vector<int> filter(const vector<int> &vec, int filter_value, bool (*ptr_func)(int, int))   
  15. {   
  16.  vector<int> temp;   
  17.  vector<int>::const_iterator iter = vec.begin();   
  18.   
  19.  while (find_if(iter, vec.end(), ptr_func(*iter, filter_value)) != vec.end())   
  20.  {   
  21.   temp.push_back(*iter);   
  22.   ++iter;   
  23.  }    
  24.  return temp;   
  25. }   
  26.   
  27. void display(vector<int> &vec)   
  28. {   
  29.  for (int ix=0; ix<vec.size(); ++ix)   
  30.   cout <<vec[ix] <<" ";   
  31.  cout <<"/n";   
  32. }   
  33.     
  34. int main()   
  35. {   
  36.  const int nsize = 5;   
  37.  int int_arr[nsize] = { 2, 4, 5, 6, 7};   
  38.  vector<int>vec(int_arr, int_arr+nsize);   
  39.  display(vec);   
  40.  vector<int>result;   
  41.   
  42.  result = filter(vec, 6, less_than);   
  43.  display(result);   
  44.     
  45.  return 0;    
  46. }  

可見,我在使用find_if()函數的時候,將裡面本應該為“函數指標”的第三個參數寫成了對這個函數的“函數調用”,這是不允許的。但整個程式的思路並沒有錯,因為上面的代碼可以通過仿函數來解決的。

上面也提到,一般通用的仿函數僅是對容器裡面的值進行處理,但本例的思路是需要將容器裡面的每個值以此與另一個值val進行比較的。所以必須要使用到函數適配器來將一個仿函數與一個值進行綁定。如下是更正後的代碼:

Code:
  1. // code snippet   
  2. #include <iostream>   
  3. #include <vector>   
  4. #include <algorithm>   
  5. #include <functional>   
  6.   
  7. using namespace std;   
  8.   
  9. bool less_than(int a, int b)   
  10. {   
  11.  return (a<b ? true:false);   
  12. }   
  13.   
  14. vector<int> filter(const vector<int> &vec, int val, less<int><)   
  15. {   
  16.  vector<int> nvec;   
  17.  vector<int>::const_iterator iter = vec.begin();   
  18.     
  19.  while ((iter=find_if(iter, vec.end(), bind2nd(lt, val))) != vec.end())   
  20.  {   
  21.   nvec.push_back(*iter);   
  22.   iter ++;   
  23.  }   
  24.  return nvec;   
  25. }   
  26.   
  27. void display(vector<int> &vec)   
  28. {   
  29.  for (int ix=0; ix<vec.size(); ++ix)   
  30.   cout <<vec[ix] <<" ";   
  31.  cout <<"/n";   
  32. }   
  33.     
  34. int main()   
  35. {   
  36.  const int nsize = 5;   
  37.  int int_arr[nsize] = { 2, 4, 5, 6, 7};   
  38.  vector<int>vec(int_arr, int_arr+nsize);   
  39.  display(vec);   
  40.  vector<int>result;   
  41.   
  42.  result = filter(vec, 6, less<int>());   
  43.  display(result);   
  44.     
  45.  return 0;    
  46. }   

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.