類模板 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()方法。