從成員函數指針生成可調用對象:function<>、mem_fn()和bind()


我們知道,普通函數指針是一個可調用對象,但是成員函數指針不是可調用對象。因此,如果我們想在一個保存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》


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM