我們知道,普通函數指針是一個可調用對象,但是成員函數指針不是可調用對象。因此,如果我們想在一個保存string的vector中找到第一個空string,不能這樣寫:
vector<string> svec; //...初始化 auto f = &string::empty; //fp是一個成員函數指針,指向string的empty函數 find_if(svec.begin(), svec.end(), fp); //錯誤 find_if算法需要一個可調用對象,但是fp是一個指向成員函數的指針
這里find_if算法查找第一個具有特定大小的元素,類似find算法,find_if算法接受一個迭代器,表示一個范圍,第三個參數是一個是一個謂詞,find_if算法對輸入序列中的每個元素調用這個指定的謂詞(可調用表達式,其返回結果是一個能用作條件的值),返回第一個使謂詞返回非0值的元素,如果不存在這樣的元素,返回尾后迭代器。簡單的說,就是從輸入序列中返回第一個滿足謂詞的值。
我們可以使用三種方式從指向成員函數的指針fp生成一個可調用對象:
1.使用function生成一個可調用對象
function<bool (const string&)> fcn = &string::empty; find_if(svec.begin(),svec.end(),fcn)
2.使用mem_fn生成一個可調用對象
mem_fn()把可以從成員指針生成一個可調用對象,與function不同,mem_fn可以根據成員指針的類型推斷可調用對象的類型,無序用戶顯式地指定:
find_if(svec.begin(), svec.end(), mem_fn(&string::empty));
使用mem_fn(&string::empty)生成一個可調用對象,該對象接受一個string實參,返回一個bool值。
mem_fn生成的可調用對象可以通過對象調用,也可以通過指針調用:
auto f = mem_fn(&string::empty); //f接受一個string或者string* f(*svec.begin()); //傳入一個string對象,f使用.*調用empty f(&svec[0]); //傳入一個string對象,f使用->*調用empty
可以認為mem_fn生成的可調用對象含有一堆重載的函數調用運算符:一個接受string*,另一個接受string&。
3.使用bind生成一個可調用對象
auto it = find_if(svec.begin(), svec.end(), bind(&string::empty,_1));
與mem_fn類似,bind生成的可調用對象的第一個實參既可以是string的指針,也可以是string的引用:
auto f = bind(&string::empty,_1); f(*svec.begin()); //正確:實參是一個string, f使用.*調用empty f(&svec[0]); //正確:實參是一個string的指針, f使用->*調用empty
下面的例子來自cplusplus上mem_fn的用法:
// mem_fn example #include <iostream> // std::cout #include <functional> // std::mem_fn struct int_holder { int value; int triple() {return value*3;} }; int main () { int_holder five {5}; // 直接調用成員函數 std::cout << five.triple() << '\n'; //15 // 使用mem_fn調用 auto triple = std::mem_fn (&int_holder::triple); std::cout << triple(five) << '\n'; //15 return 0; }
參考:http://www.cplusplus.com/reference/functional/mem_fn/
《C++ primer》