在完成了初版的《在C++中使用libuv时对回调的处理》以后,在对项目进行开发的时候,仍是感受有一些难受。html
由于在实际操做的时候,须要构建一个结构体,而且须要对这个结构体的内存进行管理,很是的麻烦。编程
在对C++的模板编程进行简单的学习后,了解到一个比较基本的知识。若是一个值或者类型能在编译的时候肯定,那么它是必定能够做为模板参数的。函数
反观我以前为了完成操做构建的结构体,能够很明显的发现,成员函数指针那一个变量是一直保持不变的,并且能够在编译的时候肯定,因此是有办法将成员函数指针放入模板里面的。学习
typedef struct { void *data; int s; } call_back_t; typedef void (*call_back_func_t)(call_back_t *t, int s, int v); int call_back_func(call_back_t *t, call_back_func_t func) { func(t, t->s, 12); return 0; }
class CallBack { public: int a = 0; void call_back(call_back_t *t, int s, int v) { std::cout << "t->s:" << t->s << std::endl; std::cout << "s:" << s << std::endl; std::cout << "v:" << v << std::endl; std::cout << "a:" << a << std::endl; } };
template<typename T, T> struct comm_call_back_s; template<typename ClassType, typename ...ArgTypes, void (ClassType::*FunType)(call_back_t *t, ArgTypes...) > struct comm_call_back_s<void (ClassType::*)(call_back_t *t, ArgTypes...), FunType> { static void comm_call_back(call_back_t *t, ArgTypes... Value) { ClassType *mClass = static_cast<ClassType *>(t->data); (mClass->*FunType)(t, std::forward<ArgTypes>(Value)...); } }; #define define_comm_call_back_s(F) (comm_call_back_s<decltype((F)), (F)>::comm_call_back)
以上代码是根据[1]中大佬代码修改得来的。首先是第一段指针
template<typename T, T> struct comm_call_back_s;
这一段代码定义了模板的原型,模板包括两个参数。一个是类型T,另外一个是类型为T的值。code
template<typename ClassType, typename ...ArgTypes, void (ClassType::*FunType)(call_back_t *t, ArgTypes...) > struct comm_call_back_s<void (ClassType::*)(call_back_t *t, ArgTypes...), FunType> { static void comm_call_back(call_back_t *t, ArgTypes... Value) { ClassType *mClass = static_cast<ClassType *>(t->data); (mClass->*FunType)(t, std::forward<ArgTypes>(Value)...); } };
第二段代码是咱们主要使用的偏特化模板。一共定义了三个模板参数,第一个是包含回调函数的类,第二个是回调函数的部分参数,第三个是回调函数。htm
在具体的特化中,咱们将回调函数的类型做为原型里面的类型T,回调函数做为值。blog
而后,咱们定义了一个comm_call_back函数做为咱们封装的回调函数。内存
#define define_comm_call_back_s(F) (comm_call_back_s<decltype((F)), (F)>::comm_call_back)
最后一段,咱们定义了一个宏,方便咱们的调用。开发
int main() { CallBack b; b.a = 100; call_back_t call; call.s = 1024; call.data = static_cast<void *>(&b); call_back_func(&call, define_comm_call_back_s(&CallBack::call_back)); }
在写完这一些代码后,我思考了几个问题,并作了必定的解答。
[1] https://stackoverflow.com/questions/9779105/generic-member-function-pointer-as-a-template-parameter