谓词函数、函数对象
從概念上講,函數(shù)對象用作函數(shù)的對象;但是從實(shí)現(xiàn)上來說,函數(shù)對象時(shí)實(shí)現(xiàn)了 operate()的類的對象。
雖然函數(shù)和函數(shù)指針也可以歸為函數(shù)對象,但實(shí)現(xiàn)了operate()的類的對象才能保存狀態(tài),才能用于STL。
我們直接看定義:
一元函數(shù):接受一個(gè)參數(shù)的函數(shù),如f(x)。
一元謂詞函數(shù):如果一元函數(shù)返回一個(gè)BOOL類型的值,則該函數(shù)稱為謂詞。
二元函數(shù):接受2個(gè)參數(shù)的函數(shù),如f(x,y)。
二元謂詞函數(shù):如果二元函數(shù)返回一個(gè)BOOL值,則該函數(shù)稱為二元謂詞。
之所以給返回布爾類型的函數(shù)對象專門命名,是因?yàn)橹^詞是用來為算法判斷服務(wù)的。
一元函數(shù):
下面給個(gè)很簡單的一元函數(shù)的例子:
template<typename elementType> void FuncDispalyElement(const elementType& element) {cout<<element<<endl; }該函數(shù)也可以采用另一種表現(xiàn)形式,即實(shí)現(xiàn)在包含在類或結(jié)構(gòu)的operate()中:
template<typename T> struct DispalyElememnt {void opearator()(const T& elememnt) const{cout<<element<<endl;} };上面兩種實(shí)現(xiàn)都可以用于STL算法for_each,將集合中的類容顯示在屏幕上。
#include <algorithm> #include <iostream> #include <vector> #include <list>using namespace std;// struct that behaves as a unary function template <typename elementType> struct DisplayElement {void operator () (const elementType& element) const{cout << element << ' ';} };int main () {vector <int> vecIntegers;for (int nCount = 0; nCount < 10; ++ nCount)vecIntegers.push_back (nCount);list <char> listChars;for (char nChar = 'a'; nChar < 'k'; ++nChar)listChars.push_back (nChar);cout << "Displaying the vector of integers: " << endl;// Display the array of integersfor_each ( vecIntegers.begin () // Start of range, vecIntegers.end () // End of range, DisplayElement <int> () ); // Unary function object cout << endl << endl;cout << "Displaying the list of characters: " << endl;// Display the list of charactersfor_each ( listChars.begin () // Start of range, listChars.end () // End of range, DisplayElement <char> () );// Unary function objectreturn 0; }其中for_each方法接受三個(gè)參數(shù),前兩個(gè)分別制定范圍的起點(diǎn)和終點(diǎn),第3個(gè)指定對范圍類的每個(gè)元素調(diào)用的函數(shù),如對vector調(diào)用DispalyElement::operate().
雖然這里2中方法都可以,但是結(jié)構(gòu)體更加強(qiáng)大,因?yàn)樗藫碛衞perate()之外,還可以擁有成員屬性,下面對之前的一元函數(shù)稍作修改:
注意:operate()不再是const成員函數(shù),因?yàn)樗鼘Τ蓡TCount進(jìn)行遞增,以記錄自己被調(diào)用用于顯示數(shù)據(jù)的次數(shù),該計(jì)數(shù)是通過共有成員屬性Count暴露的。下面是一個(gè)例子:
#include<algorithm> #include<iostream> #include<vector> using namespace std;template<typename elementType> struct DisplayElementKeepCount {int Count;// ConstructorDisplayElementKeepCount() : Count(0) {}// Display the element, hold count!void operator()(const elementType& element){++ Count;cout << element<< ' ';} };int main() {vector<int> vecIntegers;for(int nCount = 0; nCount< 10; ++ nCount)vecIntegers.push_back(nCount);cout << "Displaying the vector of integers: "<< endl; // Display the array of integersDisplayElementKeepCount<int> Result;Result = for_each( vecIntegers.begin() // Start of range, vecIntegers.end() // End of range// ,Result); //也可以用這行代替下一行, DisplayElementKeepCount<int>() );// function object cout << endl<< endl;// Use the state stores in the return value of for_each!cout << "'"<< Result.Count<< "' elements were displayed!"<< endl;return 0; }注意這次試用了for_each的返回值。
一元謂詞
知道了一元函數(shù),一元謂詞也就很好理解了,下面我么給個(gè)例子,然后將一元謂詞用于std::find_if算法中:
structure as a unary predicate template <typename numberType> struct IsMultiple {numberType Divisor;IsMultiple (const numberType& divisor){Divisor = divisor;}bool operator () (const numberType& element) const{// Check if the dividend is a multiple of the divisorreturn ((element % Divisor) == 0);} };#include <algorithm> #include <vector> #include <iostream> using namespace std; int main () {vector <int> vecIntegers;cout << "The vector contains the following sample values: ";// Insert sample values: 25 - 31for (int nCount = 25; nCount < 32; ++ nCount){vecIntegers.push_back (nCount);cout << nCount << ' ';}cout << endl << "Enter divisor (> 0): ";int Divisor = 2;cin >> Divisor;// Find the first element that is a multiple of 4 in the collectionauto iElement = find_if ( vecIntegers.begin (), vecIntegers.end (), IsMultiple<int>(Divisor) ); if (iElement != vecIntegers.end ()){cout << "First element in vector divisible by " << Divisor;cout << ": " << *iElement << endl;}return 0; }二元函數(shù)與二元謂詞
與一元函數(shù)一元謂詞一模一樣,只是參數(shù)變?yōu)?個(gè),下面給出一個(gè)二元謂詞對字符串vector排序的例子。
#include <algorithm> #include <string> using namespace std;class CompareStringNoCase { public:bool operator () (const string& str1, const string& str2) const{string str1LowerCase;// Assign space str1LowerCase.resize (str1.size ());// Convert every character to the lower case transform (str1.begin (), str1.end (), str1LowerCase.begin (), tolower);string str2LowerCase;str2LowerCase.resize (str2.size ());transform (str2.begin (), str2.end (), str2LowerCase.begin (), tolower);return (str1LowerCase < str2LowerCase);} };#include <vector> #include <iostream>template <typename T> void DisplayContents (const T& Input) {for(auto iElement = Input.cbegin() // auto, cbegin and cend: c++11 ; iElement != Input.cend (); ++ iElement )cout << *iElement << endl; }int main () {// Define a vector of string to hold namesvector <string> vecNames;// Insert some sample names in to the vectorvecNames.push_back ("jim");vecNames.push_back ("Jack");vecNames.push_back ("Sam");vecNames.push_back ("Anna");cout << "The names in vector in order of insertion: " << endl;DisplayContents(vecNames);cout << "Names after sorting using default std::less<>: " << endl;sort(vecNames.begin(), vecNames.end());DisplayContents(vecNames);cout << "Names after sorting using predicate that ignores case:" << endl;sort(vecNames.begin(), vecNames.end(), CompareStringNoCase());DisplayContents(vecNames);return 0; }小結(jié):
一元謂詞大量用于stl算法中,例如std::partition算法使用一元謂詞來劃分,stable_partition也使用一元謂詞,還有諸如find_if()等查找,remove_if()等
刪除元素的函數(shù)也使用一元謂詞。對于二元謂詞,同樣也是,如刪除響鈴重復(fù)元素unique(),排序算法sort(),以及對2個(gè)范圍進(jìn)行操作的transform(),都需要二元謂詞。謂詞在stl中很有用途。
總結(jié)
- 上一篇: javascript核心
- 下一篇: VR與AI的激情相遇