首页 > 代码库 > 谓词函数、函数对象

谓词函数、函数对象

从概念上讲,函数对象用作函数的对象;但是从实现上来说,函数对象时实现了 operate()的类的对象。
虽然函数和函数指针也可以归为函数对象,但实现了operate()的类的对象才能保存状态,才能用于STL。

我们直接看定义:
一元函数:接受一个参数的函数,如f(x)。

一元谓词函数:如果一元函数返回一个BOOL类型的值,则该函数称为谓词。

二元函数:接受2个参数的函数,如f(x,y)。

二元谓词函数:如果二元函数返回一个BOOL值,则该函数称为二元谓词。


之所以给返回布尔类型的函数对象专门命名,是因为谓词是用来为算法判断服务的。

一元函数:

下面给个很简单的一元函数的例子:

template<typename elementType>void FuncDispalyElement(const elementType& element){    cout<<element<<endl;}

该函数也可以采用另一种表现形式,即实现在包含在类或结构的operate()中:

template<typename T>struct DispalyElememnt{    void opearator()(const T& elememnt) const    {        cout<<element<<endl;    }};

上面两种实现都可以用于STL算法for_each,将集合中的类容显示在屏幕上。

#include <algorithm>#include <iostream>#include <vector>#include <list>using namespace std;// struct that behaves as a unary functiontemplate <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 integers    for_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 characters    for_each ( listChars.begin ()        // Start of range          , listChars.end ()        // End of range          , DisplayElement <char> () );// Unary function object    return 0;}

其中for_each方法接受三个参数,前两个分别制定范围的起点和终点,第3个指定对范围类的每个元素调用的函数,如对vector调用DispalyElement::operate().
虽然这里2中方法都可以,但是结构体更加强大,因为它除了拥有operate()之外,还可以拥有成员属性,下面对之前的一元函数稍作修改:

te<typename elementType>struct DisplayElementKeepCount{   int Count;   // Constructor   DisplayElementKeepCount() : Count(0) {}   // Display the element, hold count!   void operator()(const elementType& element)   {      ++ Count;      cout << element<<  ;   }};

注意:operate()不再是const成员函数,因为它对成员Count进行递增,以记录自己被调用用于显示数据的次数,该计数是通过共有成员属性Count暴露的。下面是一个例子:

#include<algorithm>#include<iostream>#include<vector>using namespace std;template<typename elementType>struct DisplayElementKeepCount{   int Count;   // Constructor   DisplayElementKeepCount() : 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 integers   DisplayElementKeepCount<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的返回值。

一元谓词

知道了一元函数,一元谓词也就很好理解了,下面我么给个例子,然后将一元谓词用于std::find_if算法中:

structure as a unary predicatetemplate <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 divisor      return ((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 - 31   for (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 collection   auto 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;}

二元函数与二元谓词

与一元函数一元谓词一模一样,只是参数变为2个,下面给出一个二元谓词对字符串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 names   vector <string> vecNames;   // Insert some sample names in to the vector   vecNames.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;}

小结:

  一元谓词大量用于stl算法中,例如std::partition算法使用一元谓词来划分,stable_partition也使用一元谓词,还有诸如find_if()等查找,remove_if()等
删除元素的函数也使用一元谓词。对于二元谓词,同样也是,如删除响铃重复元素unique(),排序算法sort(),以及对2个范围进行操作的transform(),都需要二元谓词。谓词在stl中很有用途。

谓词函数、函数对象