1.实现function需要用到的相关技术
建议看本文之前,需要先了解C++11 function或者boost::function模板的基本用法,也最好看一下我的另外一篇文章:
c++11 function模板:模板特化与可变参数函数模板
如果你使用过C++11 function模板或者boost :: function, 你一定会惊讶于这个模板对函数回调带来的方便,可能也会好奇这个功能到底是怎么实现的。我觉得还是有必要研究一下背后的实现原理,因为这背后的实现用到了很多C++语言编程骚操作(语言特性和技巧)。主要体现在如下几个方面:
- 函数对象(仿函数)
- 虚函数与多态
- 模板技术
- 函数重载
- 不定模板参数
2.function实现
2.1 公共接口的实现
实现一个抽象基类,作为调用的接口,然后从这个积累派生出几个不同的子类,从而实现对不同形式的调用。考虑到调用的函数的参数是不确定的,因此采用了不定模板参数。
// 模板参数R 表示函数的返回值类型
// 模板参数Arg 表示函数的入参类型
template <typename R, typename... Arg>
class invoker_base {
public:
virtual R operator()(Arg... arg)=0;
};
2.2 实现对普通函数的调用
template <typename R, typename... Arg>
class function_ptr_invoker
: public invoker_base<R,Arg...> {
typedef R (*funcType)(Arg...);
funcType func_;
public:
function_ptr_invoker(funcType func):func_(func) {}
// 重写基类的调用接口,用于对普通函数的调用
R operator()(Arg... arg) {
return (func_)(arg...);
}
};
2.3 实现对函数对象的调用
// 处理函数对象的版本
template <typename R, typename Arg, typename T>
class function_object_invoker :
public invoker_base<R,Arg> {
T t_;
public:
function_object_invoker(T t):t_(t) {}
// 重写基类的调用接口,用于对函数对象调用
R operator()(Arg arg) {
return t_(arg);
}
};
2.4 实现对成员函数的调用
// 实现对类成员函数的调用
template <typename R, typename T, typename... Arg>
class member_ptr_invoker :
public invoker_base<R,Arg...> {
typedef R (T::*memfuncType)(Arg...);
memfuncType func_;
T* t_;
public:
member_ptr_invoker(memfuncType func,T* t)
:func_(func),t_(t) {}
// 重写基类的调用接口,用于对类成员函数的调用
R operator()(Arg... arg) {
return (t_->*func_)(arg...);
}
};
2.5 对不同类型函数调用的测试
到目前为止,通过虚函数,实现了对普通函数、函数对象以及类成员函数的统一调用接口了,可以通过如下方法实现对不同类型的统一调用:
// 根据pBase指向的对象的不同,调用不同的函数。
// pBase可以指向保存普通函数的对象、保存类成员函数的对象或
// 保存函数对象的对象。
pBase->operator()("hello");
完整代码如下:
#include <iostream>
#include <functional>
using namespace std;
// 实现一个抽象基类,作为调用的接口,然后从这个积累派生出几个不同的子类,从而实现对不同形式的调用
template <typename R, typename... Arg> class invoker_base {
public:
virtual R operator()(Arg... arg)=0;
};
template <typename R, typename... Arg> class function_ptr_invoker
: public invoker_base<R,Arg...> {
typedef R (*funcType)(Arg...);
funcType func_;
public:
function_ptr_invoker(funcType func):func_(func) {}
R operator()(Arg... arg) {
return (func_)(arg...);
}
};
// 处理函数对象的版本
template <typename R, typename T, typename... Arg>
class function_object_invoker :
public invoker_base<R,Arg...> {
T t_;
public:
function_object_invoker(T t):t_(t) {}
R operator()(Arg... arg) {
return t_(arg...);
}
};
// 实现对类成员函数的调用
template <typename R, typename T, typename... Arg>
class member_ptr_invoker :
public invoker_base<R,Arg...> {
typedef R (T::*memfuncType)(Arg...);
memfuncType func_;
T* t_;
public:
member_ptr_invoker(memfuncType func,T* t)
:func_(func),t_(t) {}
R operator()(Arg... arg) {
return (t_->*func_)(arg...);
}
};
/* 用于测试的函数 */
// 测试普通函数
bool some_function(const std::string s) {
std::cout << s << " This is a common function \n";
return true;
}
// 测试类成员函数
class some_class {
public:
bool some_function(const std::string s) {
std::cout << s << " This is a member function \n";
return true;
}
};
// 测试函数对象
class some_function_object {
public:
bool operator()(const std::string s) {
std::cout << s <<
" This is a function object \n";
return true;
}
};
int main()
{
invoker_base<bool, string>* pBase;
// 调用类成员函数
some_class s;
pBase = new member_ptr_invoker<bool, some_class, string>(some_class::some_function, &s);
pBase->operator()("hello");
// 调用普通函数
pBase = new function_ptr_invoker<bool, string>(some_function);
pBase->operator()("hello");
// 调用函数对象
some_function_object func_obj;
pBase = new function_object_invoker<bool, some_function_object, string>(func_obj);
pBase->operator()("hello");
return 0;
}
打印结果:
2.6 对函数接口进行包装
截止到一步,显然离我们最终的目标还有些差距。虽然到目前为止,我们可以将基类指针指向不同的对象,从而实现对不同类型函数调用,但是我们最终的目的是希望模板能够根据我们传入参数的类型(普通函数、函数对象或者是成员函数)能够进行自动创建相应的对象。于是,我们要需要对接口做一些包装工作。这里主要需要用到模板的重载技术。
template <typename R, typename Arg> class function1 {
invoker_base<R,Arg>* invoker_;
public:
function1(R (*func)(Arg)) :
invoker_(new function_ptr_invoker<R,Arg>(func)) {}
template <typename T> function1(R (T::*func)(Arg),T* p) :
invoker_(new member_ptr_invoker<R,Arg,T>(func,p)) {}
template <typename T> function1(T t) :
invoker_(new function_object_invoker<R,Arg,T>(t)) {}
R operator()(Arg arg) {
return (*invoker_)(arg);
}
~function1() {
delete invoker_;
}
};
包装之后测试如下:
注意对比与包装之前的区别。可以看到对接口包装之后,可以根据我们传入的参数类型自动创建相关类型的对象,不再需要我们自己根据类型去创建具体的不同子类对象。
invoker_base<bool, string>* pBase;
// 调用类成员函数
some_class s;
// pBase = new member_ptr_invoker<bool, some_class, string>(some_class::some_function, &s);
// pBase->operator()("hello");
function1<bool, string> memfunc(some_class :: some_function, &s);
memfunc("hello");
// 调用普通函数
// pBase = new function_ptr_invoker<bool, string>(some_function);
// pBase->operator()("hello");
function1<bool, string> commonfunc(some_function);
commonfunc("hello");
// 调用函数对象
some_function_object func_obj;
// pBase = new function_object_invoker<bool, some_function_object, string>(func_obj);
// pBase->operator()("hello");
function1<bool, string> objfunc(func_obj);
objfunc("hello");
2.8 对接口做一些调整
不知道有没有注意到,c++11或boost::function中对模板参数的传入类型如下:
// 注意 <>内的形式
function<bool(string)> f;
但是我们上面实现的function1模板参数的传入类型是下面这样的:
function<bool, string> f;
显示第一种形式更直观,所以我们还得最我们的实现做一些调整。
主要需要用到模板特化技术。
// 定义一个主模板
template <typename R, typename... Arg>
class function1;
// 然后对模板参数进行特化
template <typename R, typename... Arg>
class function1<R(Arg...)> {
// 特化模板中的其它实现完全不变
};
经过上面的调整之后,就可以按照下面的方式使用模板了:
// 调用类成员函数
some_class s;
function1<bool(string)> memfunc(some_class :: some_function, &s);
memfunc("hello");
// 调用普通函数
function1<bool(string)> commonfunc(some_function);
commonfunc("hello");
// 调用函数对象
some_function_object func_obj;
function1<bool(string)> objfunc(func_obj);
objfunc("hello");
附 完整代码
#include <iostream>
#include <functional>
using namespace std;
// 实现一个抽象基类,作为调用的接口,然后从这个积累派生出几个不同的子类,从而实现对不同形式的调用
template <typename R, typename... Arg> class invoker_base {
public:
virtual R operator()(Arg... arg)=0;
};
template <typename R, typename... Arg> class function_ptr_invoker
: public invoker_base<R,Arg...> {
typedef R (*funcType)(Arg...);
funcType func_;
public:
function_ptr_invoker(funcType func):func_(func) {}
R operator()(Arg... arg) {
return (func_)(arg...);
}
};
// 处理函数对象的版本
template <typename R, typename T, typename... Arg>
class function_object_invoker :
public invoker_base<R,Arg...> {
T t_;
public:
function_object_invoker(T t):t_(t) {}
R operator()(Arg... arg) {
return t_(arg...);
}
};
// 实现对类成员函数的调用
template <typename R, typename T, typename... Arg>
class member_ptr_invoker :
public invoker_base<R,Arg...> {
typedef R (T::*memfuncType)(Arg...);
memfuncType func_;
T* t_;
public:
member_ptr_invoker(memfuncType func,T* t)
:func_(func),t_(t) {}
R operator()(Arg... arg) {
return (t_->*func_)(arg...);
}
};
/* 用于测试的函数 */
// 测试普通函数
bool some_function(const std::string s) {
std::cout << s << " This is a common function \n";
return true;
}
// 测试类成员函数
class some_class {
public:
bool some_function(const std::string s) {
std::cout << s << " This is a member function \n";
return true;
}
};
// 测试函数对象
class some_function_object {
public:
bool operator()(const std::string s) {
std::cout << s <<
" This is a function object \n";
return true;
}
};
template <typename R, typename... Arg>
class function1;
template <typename R, typename... Arg>
class function1<R(Arg...)> {
invoker_base<R,Arg...>* invoker_;
public:
// 对普通函数进行重载
function1(R (*func)(Arg...)) :
invoker_(new function_ptr_invoker<R,Arg...>(func)) {}
// 对类成员函数进行重载
template <typename T>
function1(R (T::*func)(Arg...),T* p) :
invoker_(new member_ptr_invoker<R,T, Arg...>(func,p)) {}
// 对函数对象进行重载
template <typename T>
function1(T t) :
invoker_(new function_object_invoker<R,T, Arg...>(t)) {}
// 对接口进行包装
R operator()(Arg... arg) {
return (*invoker_)(arg...);
}
~function1() {
delete invoker_;
}
};
int main()
{
// 调用类成员函数
some_class s;
function1<bool(string)> memfunc(some_class :: some_function, &s);
memfunc("hello");
// 调用普通函数
function1<bool(string)> commonfunc(some_function);
commonfunc("hello");
// 调用函数对象
some_function_object func_obj;
function1<bool(string)> objfunc(func_obj);
objfunc("hello");
return 0;
}
参考资料:
1、boost::function用法详解
2、关于c++11 std::function的模板参数 <_Res(_ArgTypes…)>