簡單的需求
比如,有一個簡單需求:找到一個vector<string>
中,長度小於3的字串的數目。解決方法可能會是:
int count(const std::vector<std::string>& str_vec, const size_t threshold)
{
int size = 0;
std::vector<std::string>::const_iterator it;
for (it = str_vec.begin(); it != str_vec.end(); ++ it) {
if (it->length() < threshold) {
++ size;
}
}
return size;
}
其實,資料STL的同學應該知道有個count_if
函式。count_if
的功能就是對於某種容器,對符合條件的元素進行計數。count_if
包含三個引數,容器的開始地址、容器的結束地址、以及引數為元素型別的函式。
使用count_if
的程式碼可以這樣寫:
bool test(const std::string& str) { return str.length() < 3; }
int count(const std::vector<std::string>& str_vec)
{
return std::count_if(str_vec.begin(), str_vec.end(), test);
}
但是,這樣有個問題:沒有擴充套件性。比如,判斷的字串由長度3變成5呢?將test
函式上面再增加一個長度引數可以嗎?不行,count_if
的實現就決定了test
必須是單一引數的。既想滿足count_if
的語法要求,又需要讓判斷的函式具有可擴充套件性,這時候就需要functor
了。
functor
登場
functor
的含義是:呼叫它就像呼叫一個普通的函式一樣,不過它的本質是一個類的例項的成員函式(operator()
這個函式),所以functor
也叫function object
。
因此以下程式碼的最後兩個語句是等價的:
class SomeFunctor
{
public:
void operator() (const string& str)
{
cout << "Hello " << str << end;
}
};
SomeFunctor functor;
functor("world"); //Hello world
functor.operator()("world"); //Hello world
其實,它並不算是STL中的一部分,不過需要STL中的函式都把functor
所謂引數之一,functor
起到了定製化的作用。functor
與其它普通的函式相比,有一個明顯的特點:可以使用成員變數。這樣,就提供了擴充套件性。
繼續上面例子,寫成functor
的形式:
class LessThan
{
public:
LessThan(size_t threshold): _threshold(threshold) {}
bool operator() (const std::string str) { return str.length() < _threshold; }
private:
const size_t _threshold;
};
int count(const std::vector<std::string>& str_vec)
{
LessThan less_than_three(3);
return std::count_if(str_vec.begin(), str_vec.end(), less_than_three);
//LessThan less_than_five(5);
//std::count_if(str_vec.begin(), str_vec.end(), less_than_five);
}
int count_v2(const std::vector<std::string>& str_vec, const size_t threshold)
{
return std::count_if(str_vec.begin(), str_vec.end(), LessThan(threshold));
}
C++11的新玩法
有人可能會說,我已經有了自己實現的判斷函式了,但是直接用又不行,有啥解決辦法嗎?
其實是有的!(我也是最近才發現的)
C++11的標準中,提供了一套函式,能將一個普通的、不符合使用方要求的函式,轉變成一個符合引數列表要求的functor
,這實在是太酷了!
比如使用者自己實現的int test(const std::string& str_vec, const size_t threshold)
函式,如果能將第二個引數進行繫結,不就符合count_if
的要求了嗎?
新標準的C++就提供了這樣一個函式——bind
。
透過std::bind
以及std::placeholders
,就可以實現轉化,樣例程式碼如下:
bool less_than_func(const std::string& str, const size_t threshold)
{
return str.length() < threshold;
}
//提供 _1 佔位符
using namespace std::placeholders;
//繫結less_than_func第二個引數為5, 轉化為functor
auto less_than_functor = std::bind(less_than_func, _1, 5);
std::cout << std::count_if(str_vec.begin(), str_vec.end(), less_than_functor) << std::endl;
參考資料
- http://www.stanford.edu/class/cs106l/course-reader/Ch13_Functors.pdf
- http://www.cplusplus.com/reference/functional/bind/
--EOF--