红魔咖啡馆

头发越掉越多,头发越掉越少

0%

【C++】函数封装与绑定

函数封装与绑定

std::function

std::function是一个通用的多态函数封装器,用于将可调用对象进行封装

语法function<R(Args...)> fname = target;

其中R为返回类型,括号内为参数类型

进行类成员函数封装时,括号内第一个参数是类引用,第二个开始才是参数类型

也可以进行类成员变量的引用

1
2
3
4
5
6
7
8
9
10
11
12
13
#include <iostream>
#include <functional>
double mul(double a, double b){
    return a*b;
}
int main(){
  // 将mul的地址保存到f1对象中
  std::function<double(double,double)> f1 = mul;
  // 通过重载调用运算符来调用mul函数
  double res = f1(1.1,2.3);
  std::cout << res << std::endl;
  return 0;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <iostream>
#include <functional>
struct Linear{
    Linear(float k, float b):k_(k),b_(b) {}
    float f(float x) {return k_* x+b_; }
    float k_, b_;
};

int main(){
    std :: function<float(Linear&, float)> mf = &Linear::f;
    Linear l(1.2,2.3);
    float res = mf(l,5);
    std :: cout << res << std :: endl;
    std :: function<float(Linear&)> k = &Linear :: k_;
    std :: cout << k(l) << std :: endl;
}

std::function实现了类型擦除:即通过单个通用接口类使用各种具体类型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <iostream>
#include <functional>
#include <map>

double add(double a, double b){
  return a+b;
}
struct substract{
  double operator()(double a, double b){return a-b;}

};

int main(){
  std::map<char, std::function<double(double,double)>>cal{
    {'+', add},
    {'-', substract()},
    {'*', [](double a, double b)->double{return a*b;}}
  };
  std::cout <<cal['+'](12.0,13)<<std::endl;
  std::cout <<cal['-'](13.0,6.2)<<std::endl;
  std::cout <<cal['+'](2.3,3.2)<<std::endl;
}

可以看到,通过std::function可以把完全不同的类型按同一个接口统一封装一个类型来使用

std::mem_fn

封装类成员可以直接使用std::mem_fn,返回一个可调用的包装器

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
#include <iostream>
#include <functional>

struct foo{
  double w;
  double cal(double a, double b){return 2*a+w*b;}
  foo& operator+=(double a){
    w+=a;
    return *this;
  }
  void print(){
    std::cout<<"w="<<w<<std::endl;
  }
};

int main(){
  foo f{1.0};
  auto memfn = std::mem_fn(&foo::cal);
  double res = memfn(f, 2.0, 3.0);
  std::cout <<"res="<<res<<std::endl;

  auto op = std::mem_fn(&foo::operator+=);
  auto f2 = op(f,2.0);
  f2.print();
}

std::bind

用于生成一个函数对象,调用该包装器时相当于调用他所包装的函数或者对象f

可以将给定的函数和参数进行绑定,调用时直接使用对应函数与参数

其中,参数可以用std::placeholders占位符占位(_1,_2…),在调用包装器时可以指定传入参数

1
2
3
4
5
6
7
8
9
10
11
12
13
#include <iostream>
#include <functional>
using namespace std::placeholders;
int sum(int a, int b, int c){
  std::cout <<"a="<<a<<", b="<<b<<", c="<<c;
  return a+b+c;
}

int main(){
  auto f = std::bind(sum, 1, _1, 3);
  int res = f(5);
  std::cout<<", res="<<res<<std::endl;
}

注意,如果直接用变量作为bind绑定,绑定后修改变量不会影响结果,因为是用值传入的

如果想用引用传入,使用cref()函数,用于返回一个变量的引用封装器s