函式物件,又叫仿函式或函式子,英文是 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,如果此函式是屬於乙個類的成員函式,那麼我們是這麼定義的 參...