什么是函数包装器
简单来说函数适配器就是基于原有函数功能的基础上,再增加一些功能。
函数适配器就实现了这一功能:将一种函数对象转化为另外一种符合要求的函数对象。
STL函数适配器(FunctionAdapters)是工具,可以帮助你修改和组合函数对象,以便更方便地在STL算法中使用。
在STL标准库中,提供了一些函数包装的模板,它们可以对函数或者可调用的对象进行包装,方便在其他的函数中调用。
function
std::function是一个通用的多态函数封装器,它将一个可调用的对象,比如函数指针,函数对象,Lambda函数等,进行封装,方便在后续的代码中调用。
下图为模板类,R为函数返回类型,函数参数类型Args,class…说明是一个可变模板参数,代表模板可以接受任意多个参数。
要实例化一个这样的模板,并定义一个函数的包装器对象,可以使用这样的方式:
function<R(Args...)> fnname = target;
target是要封装的目标函数指针或者函数对象。
有了fnname对象,就可以通过调用它的重载的函数调用运算符,从而调用target函数。
代码示例
#include <functional>
#include <iostream>
double multiply(double a, double b)
{
return a * b;
}
int main()
{
std::function<double(double, double)> func1 = multiply;
double res = func1(1.1, 2.3);
std::cout << res << std::endl;
return 0;
}
function也可以封装类的成员函数和成员变量
#include <functional>
#include <iostream>
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); //使用my来调用类对象的函数
std::cout << res << std::endl;
//封装成员变量
std::function<float(Linear&)> k = &Linear::k_;
std::cout << k(l) << std::endl;
}
类型擦除模式
可以通过单个通用接口,来使用各种具体类型。
#include <map>
#include <functional>
#include <iostream>
using namespace std;
float add(float a, float b)
{
return a + b;
}
struct Substract {
float operator()(float a, float b) { return a - b; }
};
int main()
{
map<char, function<double(double, double)>> calculator{
{'+',add},
{'-',Substract()},
{'*',[](double a,double b)->double {return a * b; }}
};
cout << calculator['+'](12.0, 13) << endl;
cout << calculator['-'](12.0, 13) << endl;
cout << calculator['*'](12.0, 13) << endl;
return 0;
}
bind
std::bind是个函数模板,它用来生成一个函数调用的转发包装器,也就是一个函数对象。调用这个包装器就相当于调用它所包装的函数或者对象f。
#include <iostream>
#include <functional>
using namespace std;
int sum(int a, int b, int c)
{
cout << "a = " << a << " b = " << b << " c = " << c << endl;
return a + b + c;
}
int main()
{
//将sum,和参数1,2,3封装到函数对象中
auto f = bind(sum, 1, 2, 3);
int res = f();
cout << "res = " << res << endl;
}
- 也使用std::placeholders的占位符_1,_2,_3来代替被绑定的实际参数,这些参数可以调用函数对象时再传入实际的参数
#include <iostream>
#include <functional>
using namespace std;
int sum(int a, int b, int c)
{
cout << "a = " << a << " b = " << b << " c = " << c << endl;
return a + b + c;
}
int main()
{
//使用std::placeholders的占位符_1,_2,_3来代替被绑定的实际参数,这些参数可以调用函数对象时再传入实际的参数
auto f = std::bind(sum, 1, std::placeholders::_1, 3);
int res = f(5);
cout << "res = " << res << endl;
}