注意:这篇文章上次更新于706天前,文章内容可能已经过时。
本文记录一下 function 函数对象的实现过程。
function 对象实际上就是对函数指针的封装,比如有如下一个函数
void hello(std::string& str)
{
std::cout << str << std::endl;
}
在主函数中这样使用 function 对象。
int main()
{
function<void(string)> func = hello;
return 0;
}
针对这种使用方法,写出对应的类模板。
// 声明一个类模板
template<typename Fty>
class myfunction{};
// 写出特化版本
template<typename R, typename A1>
class myfunction<R(A1)>
{
public:
// typedef R(* PFUNC)(A1); 声明函数指针类型 或者使用 using 关键字
using PFUNC = R(*)(A1);
// 构造函数中接收函数指针
myfunction(PFUNC pfunc): _pfunc(pfunc){}
// 重载小括号
// 返回值类型是 R, 形参类型是 A1
R operator(A1 arg)
{
return _pfunc(arg);
}
private:
PFUNC _pfunc;
}
如果传入的函数是下面这样的
int add(int a,int b)
{
return a + b;
}
写出对应的特化版本也很简单。
template<typename R,typename A1,typename A2>
class myfunction<R,A1,A2>
{
public:
using PFUNC = R(*)(A1,A2);
myfunction(PFUNC pfunc): _pfunc(pfunc){}
R operator()(A1 arg1, A2 arg2)
{
return _pfunc(arg1,arg2);
}
private:
PFUNC _pfunc;
}
写到这里,想必大家都想到了一个问题,就是函数指针的类型是无穷的,没办法写出无穷个特例化版本。
对这个问题进行简单的抽象,一个函数指针其实就是包括 返回值类型 和 参数列表。上面的两个特例化版本中唯一的不同也就是形参列表的不同。 C++11 的可变模板参数提供了解决方案。
// 返回值类型 R, 可变参数类型 A
// 注意 ... 的位置
template<typename R,typename... A >
class myfunction<R(A...)>
{
public:
// 声明函数指针类型
using PFUNC = R(*)(A...);
myfunction(PFUNC pfunc): _pfunc(pfunc){}
// 重载小括号
// 返回值类型 R,参数列表类型 A...
// 也是注意 ... 的位置
R operator()(A... arg)
{
return _pfunc(arg...);
}
private:
PFUNC _pfunc;
}