C 的函式物件

2021-10-10 23:45:00 字數 3469 閱讀 2650

函式物件,又叫仿函式或函式子,英文是 function object 或 functor.

乙個實現了函式呼叫操作符(即 operator()) 的類或結構體,就是仿函式。

operator () 就叫做函式呼叫操作符,英文是 function call operator.

下面是乙個例子。

#include

#include

#include

#include

#include

using

namespace std;

bool

cmp_func_ptr

(const

int& a,

const

int& b)

struct mycmp };

struct myhash };

intmain()

; std::

sort

(vec.

begin()

, vec.

end(),

mycmp()

);// sort()的第3個引數是乙個二元函式,故傳遞函式物件的臨時物件

for(

auto v : vec)

cout << endl;

vec =

; std::

sort

(vec.

begin()

, vec.

end(

), m1)

;// 傳臨時物件可以,傳普通物件當然也可以

for(

auto v : vec)

cout << endl;

vec =

; std::

sort

(vec.

begin()

, vec.

end(

), cmp_func_ptr)

;// 傳函式指標給sort

for(

auto v : vec)

cout << endl;

std::unordered_mapint, myhash> umap;

// unordered_map的第3個引數是函式物件型別

umap[

"tom"]=

20;umap[

"kitty"]=

12;for(

auto v : umap)

cout << endl;

return0;

}

注意,

stl標準庫中已定義了乙個函式物件,就是std::function. 它的作用是把任意可呼叫元素(如函式或函式指標)封裝進乙個可拷貝的物件。下面給乙個 std::function 的例子。

#include

#include

#include

#include

using

namespace std;

size_t hash_fn

(const string & s )

intmain

(int argc,

char

* ar**)

return0;

}

因為 unordered_map 的第3個模板引數是乙個一元函式物件(即乙個類或結構體的型別),而 hash_fn 是乙個一元函式,所以在上例中,我們用 std::function《函式簽名》 將 hash_fn 函式轉為了函式物件。

另外,使用decltype(&hash_fn)可以起到和function相同的效果。

有2個原因:

函式物件可以有自己的狀態,即利用它的成員變數來記錄狀態,這樣可以實現一些複雜的功能。

而函式沒有辦法記錄狀態,除非借助於全域性變數。

利用內部狀態可以實現一些複雜的功能,比如,乙個函式物件在多次的呼叫中可以共享這個狀態。

不過需要注意一點,在stl中都是傳值的,所以函式物件也是作為乙個值而被拷貝傳入的;假如函式物件的內部狀態在函式物件被呼叫時會發生改變,則很可能因為每次傳入給呼叫者時,函式物件的內部狀態都會被初始化而導致錯誤(見參考文獻2中的例子)。所以,函式物件的使用者的行為最好不要依賴於函式物件的內部狀態。當然,若函式物件的內部狀態根本不會改變,那即使依賴也沒有問題。

stl中不少容器的模板引數都是函式物件,而不是函式指標,因此我們需要使用函式物件。

例子有上面的 unordered_map 的模板引數,又比如,set的模板引數,priority_queue 的模板引數,等等。

那麼,為什麼stl中要使用函式物件呢?為了元件技術中的可適配性(adapability),即將某些修飾條件加諸其上而改變狀態。

在侯捷的《stl原始碼剖析》的1.9.6節和第8章對此有所闡述。

下面就「利用函式物件的內部狀態」給乙個例子。

#include

#include

#include

using

namespace std;

class

noless

bool

operator()

(int value)

const

private

:int m_min;};

template

<

typename t>

void

print_vec

(vector vec)

cout << endl;

}int

main()

; vector<

int> vec2 = vec1;

vec1.

erase

(remove_if

(vec1.

begin()

, vec1.

end(),

noless(3

)), vec1.

end())

; vec2.

erase

(remove_if

(vec2.

begin()

, vec2.

end(),

noless(4

)), vec2.

end())

;print_vec

(vec1)

;// 1 2

print_vec

(vec2)

;// 1 2 3

return0;

}

上例中,2個函式物件的內部狀態各不相同,乙個是3,乙個是4,而這2個函式物件都屬於同一種型別的函式物件。

好了,關於函式物件的基礎內容,大概就是這些了。而關於函式物件的使用的實際的例子,還可以再看看參考文獻7.

《stl原始碼剖析》

(完)

c 函式物件

標準庫里的count if可以統計容器中滿足特定條件的元素的個數。例如要統計乙個整數vector ivec中正數的個數,可以先寫乙個返回型別為bool,含有乙個int引數的條件函式 class pred 這樣,剛才的統計語句就應該寫成 count if ivec.begin ivec.end pre...

C 函式物件

標準庫里的count if可以統計容器中滿足特定條件的元素的個數。例如要統計乙個整數vector ivec中正數的個數,可以先寫乙個返回型別為bool,含有乙個int引數的條件函式 bool pred int val 之後可以用count if ivec.begin ivec.end pred 計算...

C 函式物件

函式物件實質上是乙個實現了operator 括號操作符過載 的類。它與函式指標用法一樣,但是它有乙個優點,函式指標不可以傳遞附加資料過去,但是在函式物件中,我們可以傳遞附加資料過去。先講解下運算子過載吧,對於運算子函式我們有兩種定義方式,1,如果此函式是屬於乙個類的成員函式,那麼我們是這麼定義的 參...