在學習到《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><)
{
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;
}