函数封装与绑定
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