C++ 謂詞(predicate) 與 仿函數 ( functor (function object))

謂詞與函數對象

謂詞 predicate

C++ 標準定義謂詞以下:html

The Predicate parameter is used whenever an algorithm expects a function object that when applied to the result of dereferencing the corresponding iterator returns a value testable as true. In other words, if an algorithm takes Predicate pred as its argument and first as its iterator argument, it should work correctly in the construct if (pred(*first)){...}. The function object pred shall not apply any non-constant function through the dereferenced iterator. This function object may be a pointer to function, or an object of a type with an appropriate function call operator.ios

換成中文就是:當一個算法須要一函數對象,去應用於解引用(deferencing)迭代器(deferencing 解釋: int p;將定義一個指向整數的指針,並p取消引用該指針,這意味着它將實際檢索p指向的數據。)的結果,謂詞參數返回一個testable值爲true。換句話說,換句話說, 若是算法將謂詞 pred 做爲其參數,first參數是迭代參數,則若是 (pred (* first)) {..} , 它應該在構造中正常工做。函數對象 pred 不該經過解引用迭代器應用於任何非定常(non-constant)函數。此函數對象能夠是指向函數的指針, 也能夠是具備適當函數調用運算符的類型的對象。算法

仿函數

functor(函數對象或函數)形式:object + ()
這包括正常函數,函數指針和 () 運算符(函數調用運算符)重載的類對象,即爲其定義函數 operator()() 類。
有時咱們能夠在普通函數不起做用時使用函數對象。STL常用函數對象並提供幾個很是有用的函數對象。
函數對象是泛型編程的力量和純抽象概念的另外一個例子。咱們能夠說任何行爲都像函數對象是函數。所以,若是咱們定義一個行爲是函數的對象,它能夠用做函數。編程

#include <iostream> 

struct absValue 
{ 
    float operator()(float f){ 
        return f> 0?f:-f; 
    } 
}; 

int main()
{ 
    using namespace std; 

    float f = -123.45; absValue aObj; 
    float abs_f = aObj(f); 
    cout <<「f =」<< f <<「abs_f =」<< abs_f << '\n'; 
    return 0; 
}

 

正如咱們從定義中看到的那樣,即便 aObj 是一個對象而不是一個函數,咱們也能夠對該對象進行調用。效果是運行由對象absValue定義的重載調用操做符。運算符獲取浮點值並返回其絕對值。請注意,函數調用運算符必須聲明爲成員函數。
所以,定義調用操做符的類類型的對象(如absValue對象)稱爲函數對象。
一個函數的行爲是能夠經過使用括號和傳遞參數來調用。app

func (arg1 , arg2);

 

若是咱們但願對象以這種方式運行,咱們必須經過使用括號和傳遞參數來調用它們。咱們所要作的就是使用適當的參數類型定義operator() :函數

Class X {
public:
    // define "function call" operator
    return-value operator() (arguments) const;
    ...
};

 

而後咱們可使用這個類的對象來表現咱們能夠調用的函數:性能

X fn; 
//... 
fn(arg1,arg2); //爲函數對象fn調用operator()

 

此調用至關於:優化

fn.operator()(ARG1,ARG2); //爲函數對象fn調用operator()

 

一個例子:spa

class Print { 
publicvoid operator()(int elem)const { 
        cout << elem <<「」; 
    } 
}; 

int main(){ 
    vector <int> vect; 
    forint i = 1; i <10; ++ i){ 
        vect.push_back(i); 
    } 

    Print print_it; 
    for_each(vect.begin(),vect.end(),print_it); 
    cout << endl; 
    return 0; 
}

 

for_each(vect.begin(),vect.end(),print_it);

 

 一般,第三個參數能夠是仿函數,而不只僅是常規函數。實際上,這提出了一個問題。咱們如何聲明第三個參數?咱們不能將它聲明爲函數指針,由於函數指針指定了參數類型。由於容器幾乎能夠包含任何類型,因此咱們事先並不知道應該使用哪一種特定類型。STL經過使用模板解決了這個問題。.net

template<class Iterator, class Function>
Function for_each(Iterator first, Iterator last, Function f) {
    while (first != last) {
        f(*first);  
        ++first;
    }
    return f;
}

 

如下是Nicolai M. Josuttis在「The C ++ Standard Library」中列出的函數對象的一些優勢。

  • 功能對象是「智能功能」。
    行爲像指針的對象是智能指針。對於行爲相似於函數的對象也是如此:它們能夠是「智能函​​數」,由於它們可能具備超出operator()的能力。函數對象能夠具備其餘成員函數和屬性。這意味着函數對象具備狀態。

  • 每一個函數對象都有本身的類型。
    普通函數只有在簽名不一樣時纔有不一樣的類型。可是,當函數對象的簽名相同時,它們能夠具備不一樣的類型。實際上,函數對象定義的每一個函數行爲都有本身的類型。這是使用模板進行泛型編程的重大改進,由於您能夠將功能行爲做爲模板參數傳遞。

  • 函數對象一般比普通函數更快。
    模板的概念一般容許更好的優化,由於在編譯時定義了更多細節。所以,傳遞函數對象而不是普通函數一般會產生更好的性能。

STL改進了仿函數概念,以下所示:
generator : 是一種能夠不帶參數調用的函數
一元函數:有一個參數的調用函數
二元函數:有兩個參數的調用函數

generator 能夠被認爲是一種 每次調用都返回 集合/序列的下一個值的函數/對象。

算法的特殊輔助函數是謂詞。謂詞是返回布爾值的函數(或者能夠隱式轉換爲bool的函數)。換句話說,謂詞類是一個仿函數類,其operator() 函數是謂詞,即其operator() 返回true或false。
謂詞在STL中被普遍使用。標準關聯容器的比較函數是謂詞,謂詞函數一般做爲參數傳遞給find_if等算法。根據其目的,謂詞是一元的或二元的。
一元函數返回一個布爾值是一元謂詞。
二元函數返回一個布爾值是二元謂詞。

謂詞的種類算法(algorithm) 的 謂詞(predicate) 詳解函數 函數指針 lambda表達式 函數對象 庫定義的函數對象

轉自:http://www.javashuo.com/article/p-gbzsawxw-gk.html

相關文章
相關標籤/搜索