函数封装与绑定
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(){ std::function<double(double,double)> f1 = 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