Re: [問題] cpp的function pointer傳遞

看板C_and_CPP作者 (髮箍)時間3年前 (2020/10/01 09:24), 3年前編輯推噓0(002)
留言2則, 1人參與, 3年前最新討論串2/3 (看更多)
物件的操作需要以下兩個資訊: 1. 物件的參考/指標 (pointer to object) 2. 該物件的成員參考/指標 (pointer to member) 因為你在 B::B_API() 裡會存取到資料成員所以要把資訊透過額外的參數傳遞 給 pfnTest_t, 這通常得做 type erasing 來降低相依性, 不需要這個資訊的 話改傳 null pointer 就好了. 這種設計在 task-based system 還蠻常見的. typedef int(*pfnTest_t)(void* context, void* x, unsigned char* y, unsigned int z); int test_api(pfnTest_t p_pfnTest, void* context); context 的內容要和 callback 實作相互搭配, 因為標準還不允許用整數型別 來儲存 pointer to member 的資訊, 在這裡只能先傳物件指標作為引數: int my_callback(void* context, void* x, unsigned char* y, unsigned int z) { return reinterpret_cast<B*>(context)->B_API(x, y, z); } B b; test_api(my_callback, std::addressof(b)); 上面的實作應該是最直覺的寫法, 但卻存在不少問題: 1. test_api() 呼叫敘述無法表達會轉呼叫 B::B_API() 這件事 2. my_callback() 和 B 耦合性太高, 修改範圍無法只侷限在一個地方 3. my_callback() 這類的 adapter function 實作數會與類別和成員組合 數呈正比 所以我們需要一種可以將類別以及成員函式資訊內嵌在函式裡方法, 並且自動 產生需要的 adapter function, 在 C++ 裡通常會用模板來實現. 因為類別是 成員函式型別的一部分, 我們只需要儲存後者即可, 前者可以透過 meta-func tion class_of<pmf> 來取得: template <auto pmf> struct class_of; template < typename Ret, typename C, typename... Args, Ret (C::*pmf) (Args...) > struct class_of<pmf> { using type = C; }; static_assert(std::is_same_v<class_of<&B::B_API>::type, B>); 接著我們就可以用 class_of<pmf> 來實作 adapter function 產生器: template <auto pmf> int delegate_to(void* context, void* x, unsigned char* y, unsigned int z) { auto* const object = reinterpret_cast< typename class_of<pmf>::type*>(context); return (object->*pmf)(x, y, z); } test_api(delegate_to<&B::B_API>, std::addressof(b)); 完整程式碼: https://wandbox.org/permlink/8vEKgUbQojKeOAwK 透過以上程式碼我們就能將更多心力放在商業邏輯, 而不用煩惱語言限制 :) -- ※ 發信站: 批踢踢實業坊(ptt.cc), 來自: 114.137.28.236 (臺灣) ※ 文章網址: https://www.ptt.cc/bbs/C_and_CPP/M.1601515469.A.170.html ※ 編輯: loveme00835 (114.137.28.236 臺灣), 10/01/2020 09:58:50

10/01 10:24, 3年前 , 1F
但是,test_api 他不能改吧?
10/01 10:24, 1F

10/01 10:25, 3年前 , 2F
把 B_API 改成 static 出錯的地方也怪怪的 @@
10/01 10:25, 2F
文章代碼(AID): #1VTI_D5m (C_and_CPP)
文章代碼(AID): #1VTI_D5m (C_and_CPP)