在完成了初版的《在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