std::function簡介與使用

類模板 std::function 是通用多態函數封裝器。 std::function 的實例能存儲、複製及調用任何可調用 (Callable) 目標——函數、 lambda 表達式、 bind 表達式或其他函數對象,還有指向成員函數指針和指向數據成員指針

std::function接收一個函數的類型,而不是函數指針,需要用函數類型實例化該模板。

std::function 滿足可複製構造 (CopyConstructible) 和可複製賦值 (CopyAssignable)

  • 首先,要區分函數指針和函數類型
void Fun1(){
  std::cout<<"Call Fun1()"<<std::endl;
}

int Fun2(std::string &str){
  std::cout<<"Call Fun2()"<<std::endl;
}

std::vector<int>& Fun3(const int a){
  std::cout<<"Call Fun3()"<<std::endl;
}

函數指針組成:返回值類型 + 函數指針名 + 函數參數類型

void (*pfunc)() = Fun1;
int (*pfunc)(std::string&) = Fun2;
std::vector<int>&(*pfunc)(const int) = Fun3;

函數類型:返回值類型 + 函數類型
Fun1的函數類型:void()
Fun2的函數類型:int(std::string&)
Fun3的函數類型:std::vector<int>&(const int)
  • 函數指針的使用
  //函數指針調用
  void(*funptr1)() = Fun1;
  funptr1();

  int(*funptr2)(std::string&) = Fun2;
  funptr2(str);

  std::vector<int>&(*funptr3)(const int) =Fun3;
  funptr3(100);
  • 用普通的函數類型去實例化std::function實例
  //用不同類型的全局函數初始化
  std::function<void()> fun1 = Fun1; 
  fun1();

  std::function<int(std::string&)> fun2 = Fun2;
  std::string str = "hello";
  fun2(str);

  std::function<std::vector<int>&(const int)> fun3 = Fun3;
  fun3(10);
  • 使用類的成員方法實例化std::function,並與 map 結合實戰
void Fun4(){
  std::cout<<"Call Fun4()"<<std::endl;
}

void Fun5(){
  std::cout<<"Call Fun5()"<<std::endl;
}

class MyFunc{
public:
  void Fun1(){
    std::cout<<"Call MyFunc::Fun1()"<<std::endl;
}
  int Fun2(std::string &str){
    std::cout<<"Call MyFunc::Fun2()"<<std::endl;
}
  std::vector<int>& Fun3(const int a){
    std::cout<<"Call MyFunc::Fun3()"<<std::endl;
}
};

int main(){
  //用類的成員函數初始化
  MyFunc mf;
  std::function<void(MyFunc*)> fun4 = &MyFunc::Fun1;
  //除靜態方法,類的成員對象的調用需要一個this指針,所以隱藏參數爲MyFunc*
  fun4(&mf);

  std::function<int(MyFunc*,std::string&)> fun5 = &MyFunc::Fun2;
  fun5(&mf,str);

  std::function<std::vector<int>&(MyFunc*,const int)> fun6 = &MyFunc::Fun3;
  fun6(&mf,9);
  std::map<int,std::function<void()>> FuncMap;
  /*
  typedef std::function<void()> MapFunc;  //這樣可以省事一些
  */
  FuncMap.insert(std::make_pair<int,std::function<void()>>(0,Fun1));
  FuncMap.insert(std::make_pair<int,std::function<void()>>(1,Fun4));
  FuncMap.insert(std::make_pair<int,std::function<void()>>(2,Fun5));

  //std::map<int,std::function<void()>>::iterator it = FuncMap.begin();
  /*
  for(;it!=FuncMap.end();++it){
      it->second();
  }
  */
  for(int i = 0 ;i<5;++i){
    auto it = FuncMap.find(i);
    if(it!=FuncMap.end()){
      it->second();//調用點
    }
  }
  return 0;
}
  • 用lambad表達式實例化function,或者說用std::function去保留某一種類型的lambda表達式
  std::function<int(int,int)> Func([](int a,int b)->int{return a+b;});
  std::cout<<Func(10,20)<<std::endl;
  • std::function去保留實例化以後的函數模板與函數模版使用

template <typename T>
void show(const T& a){
  std::cout << a << std::endl;
}

std::function<void(int)> funcc = show<int>;
//首先指定模版函數的類型,編譯器生成一個int類型的show方法,然後被std::function保留下來
funcc(99);
  • std::function保存自定義函數對象
class MyGreater{
public:
bool operator()(int& i, int& j)const{
		return i > j;
}
};


  std::vector<int> vec;
  for(int i =0 ;i<10;++i){
    vec.push_back(i);
  }
  for(auto val:vec){
    std::cout<<val<<" ";
  }
  std::cout<<"\n";
  std::function<bool(int,int)> fun_ = MyGreater();
  
  std::sort(vec.begin(),vec.end(),fun_);
  for(auto val:vec){
    std::cout<<val<<" ";
  }
  std::cout<<"\n";

//如果MyGreater是類模板,實例化function時:
std::function<bool(int,int)> func = MyGreater<int>();

總結一句話:
std::function可以保留可調用目標,包括如生命週期等於語句的生命週期的lambada表達式等。使用的時候用可調用目標的類型(函數類型)去實例化一個function類,調用的時候實際上調用的是生成function對象的operator()方法

參考鏈接: std::function

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章