在C 中對仿函式的理解

2021-10-03 15:53:00 字數 3104 閱讀 5857

先考慮乙個簡單的例子:假設有乙個vector,你的任務是統計長度小於5的string的個數,如果使用count_if函式的話,你的**可能長成這樣:

bool

lengthislessthanfive

(const string& str)

int res=

count_if

(vec.

begin()

, vec.

end(

), lengthislessthanfive)

;

其中count_if函式的第三個引數是乙個函式指標,返回乙個bool型別的值。一般的,如果需要將特定的閾值長度也傳入的話,我們可能將函式寫成這樣:

bool

lenthislessthan

(const string& str,

int len)

這個函式看起來比前面乙個版本更具有一般性,但是他不能滿足count_if函式的引數要求:count_if要求的是unary function(僅帶有乙個引數)作為它的最後乙個引數。所以問題來了,怎麼樣找到以上兩個函式的乙個折中的解決方案呢?

這個問題其實可以歸結於乙個data flow的問題,要設計這樣乙個函式,使其能夠access這個特定的length值,回顧我們已有的知識,有2種解決方案可以考慮:

函式的引數

這種方法我們已經討論過了,多個引數不適用於count_if函式。

全域性變數

我們可以將長度閾值設定成乙個全域性變數,**可能像這樣:

int maxlength;

bool

lengthislessthan

(const string& str)

int res=

count_if

(vec.

begiin()

, vec.

end(

), lengthislessthan)

;

這段**看似很不錯,實則不符合規範,最重要的是,它不優雅。原因有以下幾點要考慮:

容易出錯;

為什麼這麼說呢,我們必須先初始化maxlength的值,才能繼續接下來的工作,如果我們忘了,則可能無法得到正確答案。此外,變數maxlength和函式lengthislessthan之間是沒有必然聯絡的,編譯器無法確定在呼叫該函式前是否將變數初始化,給碼農平添負擔。

沒有可擴充套件性;

如果我們每遇到乙個類似的問題就新建乙個全域性變數,尤其是多人合作寫**時,很容易引起命名空間汙染(namespace polution)的問題;當範圍域內有多個變數時,我們用到的可能不是我們想要的那個。

全域性變數的問題;

每當新建乙個全域性變數,即使是為了coding的便利,我們也要知道我們應該盡可能的少使用全域性變數,因為它的cost很高;而且可能暗示你這裡有一些待解決的優化方案。

說了這麼多,還是要回到我們原始的那個問題,有什麼解決方案呢?答案當然就是這篇部落格的正題部分:仿函式

標頭檔案:#include 
我們的初衷是想設計乙個unary function,使其能做binary function的工作,這看起來並不容易,但是仿函式能解決這個問題。

先來看仿函式的通俗定義:仿函式(functor)又稱為函式物件(function object)是乙個能行使函式功能的類。仿函式的語法幾乎和我們普通的函式呼叫一樣,不過作為仿函式的類,都必須過載operator()運算子,舉個例子:

class

func};

func myfunc;

myfunc

("helloworld!");

>>

>helloworld!

仿函式其實是上述解決方案中的第四種方案:成員變數。成員函式可以很自然的訪問成員變數:

class

void

operator()

(const string& str)

const

private

:const string ss;};

("is world");

myfunc

("hello");

>>

>hellois world

我相信這個例子能讓你體會到一點點仿函式的作用了;它既能想普通函式一樣傳入給定數量的引數,還能儲存或者處理更多我們需要的有用資訊。

讓我們回到count_if的問題中去,是不是覺得問題變得豁然開朗了?

class

shorterthan

bool

operator()

(const string& str)

const

private

:const

int length;};

count_if

(myvector.

begin()

, myvector.

end(),

shorterthan

(length));

//直接呼叫即可

這裡需要注意的是,不要糾結於語法問題:shorterthan(length)似乎並沒有呼叫operator()函式?其實它呼叫了,建立了乙個臨時物件。你也可以自己加一些輸出語句看一看。

相比用函式指標去處理,仿函式多了很多的靈活性,而且stl中也預先實現了一些仿函式

在c++11裡面可以通過lambda表示式解決上述問題:

#include

#include

#include

#include

using

namespace std;

intmain()

;int x =5;

int k=std::

count_if

(c.begin()

, c.

end(),

[x](

int n));

cout << k << endl;

return0;

}

比仿函式方便多了

c 中仿函式的理解

2016年11月11日 17 47 25 1341人閱讀收藏 舉報c 基礎 7 先考慮乙個簡單的例子 假設有乙個vector,你的任務是統計長度小於5的string的個數,如果使用count if函式的話,你的 可能長成這樣 1 bool lengthislessthanfive const str...

仿函式 C 中仿函式的應用

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

C 中的 sort函式 函式指標 仿函式

sort函式有2種常見的寫法,一種是不帶參的,也就是預設的公升序,一種是傳入函式指標的,用函式自定義排序規則。示例 include include includeusing namespace std class cmp bool cmp2 int a,int b 從大到小 int main sor...