std::function實現原理簡述

實際上,每個function實例都根據函數類型的中返回值和參數類型推演出一個特例化,然後用類的成員變量去保留用這個函數類型的產生的函數指針,使用的時候實際上調用該類的小括號運算符重載operator()

int sum(int a,int b){
  return a+b;
}

template <typename R>
class MyFunction{};

/*
部分特例化
R:operator()的返回值,Arg1,Arg1爲operator()的形參類型
*/
template <typename R,typename Arg1,typename Arg2>
class MyFunction<R(Arg1,Arg2)>{
public:
  using Pfunc = R(*)(Arg1,Arg2); //定義用戶傳入的對於函數類型的函數指針 
  //typedef R(*Pfunc)(Arg...);
  MyFunction(Pfunc pfunc):pfunc_(pfunc){
    cout<<"call MyFunction(Pfunc pfunc)"<<"\n";
  }
  R operator()(Arg1 a1,Arg2 a2){
    cout <<"R operator()(Arg1 a1,Arg2 a2)"<<endl;
    return pfunc_(a1,a2);
  }
private:
  Pfunc pfunc_;//用來保留外部傳入的可調用目標
};

使用時和標準庫中無差別:

int main(){
  //使用標準庫中的function來保留可調用目標類的成員變量
  std::function<int(int,int)>  func1 = sum;
  cout<<func1(10,10)<<endl;;

  //使用自定義的fuction來保留可調用目標到類的成員變量
  MyFunction<int(int,int)> func2 = sum;
  cout<<func2(10,20)<<endl; //func2.operator()(10,20)
  return 0;
}

上面的方式可以滿足我們的需求,但是這樣有個缺點,std::function保留的可調用目標的參數個數是不確定的返回值肯定只能有一個,不能每次都根據不同的參數個數,去產生一大堆不一樣的部分特例化,這樣顯然是不現實。c++11提供了模板可變參,可以將上面模板修改如下:

template <typename R,typename... Arg>
class MyFunction<R(Arg...)>{
public:
  using Pfunc = R(*)(Arg...); //定義用戶傳入的對於函數類型的函數指針 
  //typedef R(*Pfunc)(Arg...);
  MyFunction(Pfunc pfunc):pfunc_(pfunc){
    cout<<"call MyFunction(Pfunc pfunc)"<<"\n";
  }
  R operator()(Arg... arg){
    cout <<"R operator()(Arg...)"<<endl;
    return pfunc_(arg...);
  }
private:
  Pfunc pfunc_;//用來保留外部傳入的可調用目標
};
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章