std::function简介与使用

类模板 std::function 是通用多态函数封装器。 std::function 的实例能存储、复制及调用任何可调用 (Callable) 目标——函数、 lambda 表达式、 bind 表达式或其他函数对象,还有指向成员函数指针和指向数据成员指针

std::function接收一个函数的类型,而不是函数指针,需要用函数类型实例化该模板。

std::function 满足可复制构造 (CopyConstructible) 和可复制赋值 (CopyAssignable)

  • 首先,要区分函数指针和函数类型
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
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)

  • 函数指针的使用
1
2
3
4
5
6
7
8
9
  //函数指针调用
  void(*funptr1)() = Fun1;
  funptr1();

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

  std::vector<int>&(*funptr3)(const int) =Fun3;
  funptr3(100);
  • 用普通的函数类型去实例化std::function实例
1
2
3
4
5
6
7
8
9
10
  //用不同类型的全局函数初始化
  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 结合实战
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
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表达式
1
2
  std::function<int(int,int)> Func([](int a,int b)->int{return a+b;});
  std::cout<<Func(10,20)<<std::endl;
  • std::function去保留实例化以后的函数模板与函数模版使用
1
2
3
4
5
6
7
8
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保存自定义函数对象
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
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