zoukankan      html  css  js  c++  java
  • 谓词函数、函数对象

    从概念上讲,函数对象用作函数的对象;但是从实现上来说,函数对象时实现了 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 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 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 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 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中很有用途。

  • 相关阅读:
    C++的几个晦涩特性
    高效学习的工具Mnemosyne
    允许OSQA上传任意类型的文件
    新一代J2ME终端标准MSAfor CLDC——解读JSR248
    JAVA实现简单的HTTP服务器
    什么是Web 2.0
    Java 手机与空间制图服务(WMS)应用集成
    广西移动SP结算工作管理流程
    2007年Enterprise 2.0的10大趋势
    移动虚拟专用网的发展与未来应用
  • 原文地址:https://www.cnblogs.com/renyuan/p/6216200.html
Copyright © 2011-2022 走看看