仿函式使用要領

2021-04-02 22:54:10 字數 3803 閱讀 5145

仿函式,又或叫做函式物件,是

stl(標準模板庫)六大元件(容器、配置器、迭代器、演算法、配接器、仿函式)之一;仿函式雖然小,但卻極大的拓展了演算法的功能,幾乎所有的演算法都有仿函式版本。例如,查詢演算法

find_if

就是對find

演算法的擴充套件,標準的查詢是兩個元素向等就找到了,但是什麼是相等在不同情況下卻需要不同的定義,如位址相等,位址和郵編都相等,雖然這些相等的定義在變,但演算法本身卻不需要改變,這都多虧了仿函式。

仿函式之所以叫做函式物件,是因為仿函式都是定義了

()函式運算操作符的類。例如,

stl自帶的仿函式

equal_to

定義為:

template

struct equal_to : public binary_function<_tp,_tp,bool> };

在演算法內部呼叫此操作符,如

find_if

:template

_stlp_inline_loop _randomaccessiter __find_if(_randomaccessiter __first, _randomaccessiter __last,

_predicate __pred,

const random_access_iterator_tag &)

仿函式的可配接性是指仿函式能夠與其它仿函式配接在一起實現新的功能,如不小於

60,可以利用

stl自帶的

not1

和less

配接而成:

not1(bind2nd(less(), 12))

。一般而言,通用函式也可以作為仿函式引數傳遞給演算法,但其區別在於「通用函式不具有可配接性」。是否定義成仿函式都具有配接性了呢?也不盡然!只有從

unary_function

或者binary_funcion

繼承的仿函式才有配接性。這是為什麼呢?

其奧妙在於模板類常見的型別定義,可配接性的關鍵就在於這些型別定義;如

binary_function

:template

struct binary_function ;

在stl

的介面卡中會自動使用到這些型別定義,所以必須宣告這些型別。

stl的實現也考慮到會將通用函式作為仿函式來使用,為了保證這些函式的可配接性,即把這些函式轉換為仿函式使用,

stl也提供了相應的介面卡

ptr_fun1_base

,ptr_fun2_base

,其原理也是過載函式呼叫操作符,在仿函式物件構造時把通用函式作為引數傳入,如:

template

class pointer_to_unary_function : public unary_function<_arg, _result> //

構造時把函式指標傳入

explicit pointer_to_unary_function(_result (*__x)(_arg)) : _m_ptr(__x) {}

//()

函式運算操作符過載,執行函式功能

_result operator()(_arg __x) const };

既然通用函式都能轉換為仿函式,帶有

c++封裝性的類的成員函式(當然要是

public

)也能否轉換為仿函式?答案是肯定的,

stl也提供了相應介面卡。由於返回值和引數的個數不同,這類介面卡的數目很多:

_void_mem_fun0_ptr

、_void_mem_fun1_ptr

、_void_const_mem_fun0_ptr

、_void_const_mem_fun1_ptr

等。例子中使用通用函式和成員函式作為仿函式配合

stl演算法使用。

class numbers //

用於查詢

bool if_equal(int val)

};如下的語句驗證了

ptr_fun

轉換後的仿函式的可配接性:

vector::iterator it = find_if(vnums.begin(), vnums.end(), bind2nd(ptr_fun(if_equal), val));

而for_each(vobjs.begin(), vobjs.end(), mem_fun(&numbers::display));

和vector::iterator itobj=find_if(vobjs.begin(), vobjs.end(), bind2nd(mem_fun1(&numbers::if_equal), 3));

說明了如何使用

stl的介面卡來轉換類成員函式。需要說明的是,在轉換成員函式時,有引用和指標兩個版本,例子程式中使用的是指標版本,所以定義

vector

時定義元素型別尾

number*

。這是因為這時介面卡的函式操作符是通過指標形式呼叫的,如

mem_fun1

返回mem_fun1_t

的內部實現為:

ret operator()(_tp* __p, _arg __x) const

上面說過定義可配接的仿函式,只需要從

unary_function

和binary_function

派生即可,但是

stl只定義了這兩種型別;但我們有可能需要使用

3個引數的仿函式,同時也更能體會可配接性的原理,這裡給出了

triple_function

的函式原型,可以

stl的作為一種擴充套件。

//用於方便提前類的型別定義

#define triple_arg(operation, type) operation::type

//三元函式的型別定義

template

struct triple_funcion;//

三元函式的介面卡,把第

3個引數固定為特定值

template

class binder3rd : public binary_function

typename triple_arg(operation, second_argument_type), typename triple_arg(operation, result_type)> //

通過固定第三個引數,把函式轉換為

binary_function

typename operation::result_type operator()(const operation::first_argument_type& x,

const operation::second_argument_type& y) const

};

//上層使用的包裝類

template

inline binder3rdbind3rd(const operation& fn, const arg& x)

在例子中定義了乙個三元仿函式:

class qualified : public triple_funcion };

用於查詢數學和物理兩科成績符合條件的學生。

查詢時,通過

bind3rd

和bind2nd

把數學和物理的成績基線定下來:數學

>40

,物理>60

。it = find_if(it, students.end(), bind2nd(bind3rd(qualified(), 40), 60));

仿函式小巧和作用大,原因是其可配接性和用於演算法;可以根據需要把相關函式封裝到類中,或者呼叫基本的函式庫來減少開發量。只要知道了

stl介面卡內部機制,就能定義出符合要求的仿函式來。

find if 仿函式的使用

有時我們要在map vector容器中查詢符合條件的記錄,map提供乙個find的成員函式,但也僅限於查詢關鍵字滿足條件的記錄,不支援值域的比較。如果我們要在值域中查詢記錄,該函式就無能無力了。而vector甚至連這樣的成員函式都沒有提供。所以一般情況下進行值域的查詢,要麼自己遍歷資料,要麼求助於s...

python 仿函式 C 仿函式

c 的標準庫stl裡面有6大部件,其中之一為仿函式。初始看到這一名字可能讓人摸不著頭腦 函式倒是挺容易理解,何故又起個仿函式的名字呢?本文將帶你揭開它看起來挺讓人迷惑但是實際上很簡單的面紗。仿函式,看名字就知道它肯定和函式有什麼關聯,但是也肯定和函式有什麼區別。函式主要是一塊接收輸入引數然後按照一定...

仿函式 C 中仿函式的應用

仿函式 c 中仿函式的應用 在使用仿函式的時候,主要用到以下兩種 一種是以基類std unary function派生出來的派生類 另一種是以基類std binary function派生出來的派生類。而這兩種有什麼區別呢?它們之間的區別只是第一種接收的引數個數為乙個,而第二種接收的引數的個數為兩個...