函数参数绑定
使用到的情景
我们在程序开发中经常遇到需要传入函数的参数与实际期望不符合的情况。如:需要传入的是无参函数int fun(int b)
,但是接口只允许传入int fun(void)
。这时候就需要用到函数对象来解决。
例子:
// 需要调用的接口 只允许传入无参函数
template<typename T>
void call_fun(T fun){
fun();
}
// 正常调用
void Myprintf(){
// ....你的操作
cout << "fun print" << endl;
}
call_fun(Myprintf);
需求
根据上例,我们需要给call_fun
接口传入一个任意的带一个参数的函数。
解决办法
我们可以使用函数对象。函数对象,顾名思义就是一个像函数的对象。实际是一个对象。但是如何使得对象,像一个函数呢? 我们可以重载() 使用operator()()
来达到目的.
对于这个例子,operator()()
不能有任何参数,因为接口call_fun()
里面调用的也是无参数的函数。但是既然这样如何做到在调用的时候传入一个参数呢?
不要忘了我们使用的是对象,是一个类。那么我们既可以给这个类设置一个属性,来保存这个需要传入的参数,在operator()()
中调用函数时传入。
例子
template<typename ReturnType, typename ParameterType>
class MyFun
{
public:
typedef ReturnType(*_FUN)(ParameterType);
// 构造函数传参
MyFun(_FUN fun,ParameterType paramater)
:m_fun(fun),m_parameter(paramater){}
// 运算符重载()
ReturnType operator()(){
return m_fun(m_parameter);
}
private:
_FUN m_fun; //保存函数
ParameterType m_parameter; // 保存参数
};
如何使用?
// 需要调用的接口
template<typename T>
void call_fun(T fun){
fun();
}
// 需要传入的函数
int print_A(int a){
// ... 你的操作
cout << a << " printf_A" << endl;
return 0;
}
// 使用方式
call_fun(MyFun<int,int>(print_A,5));
扩展
按照上面的例子,如果需要调用call_fun()接口传入代两个参数的函数怎么办? 给函数对象在增加一个属性,保存第二参数,。。。。读者可以停下来思考一下。
如果使用的接口是需要一个参数的函数,而我们实际要传入的是两个参数的函数甚至更多需要怎么办? 这里的重点是接口需要的函数参数类型函数个数,与你定义的函数对象重载的operater()
的参数类型参数个数保持一致。你需要几个参数在函数对象内增加几个属性,然后在operater()
内调用函数时传入。
重点在函数对象的operater()
与接口需求相同,对象的内部设计可以根据自己喜好随意实现。
再优化
当你感觉每次都手动生成MyFun这个函数对象,封装一下。使用模板函数简化调用。模板函数内创建函数对象。
例子
template<typename ReturnType, typename ParameterType>
MyFun<ReturnType,ParameterType> bind(ReturnType(*_fun)(ParameterType), ParameterType parameter){
return MyFun<ReturnType,ParameterType>(_fun, parameter);
}
// 这时候的调用
call_fun(bind(print_A, 5));