實際上,每個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_;//用來保留外部傳入的可調用目標
};