作者loveme00835 (髮箍)
看板C_and_CPP
標題Re: [問題] cpp的function pointer傳遞
時間Thu Oct 1 09:24:17 2020
物件的操作需要以下兩個資訊:
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
→ Lipraxde: 但是,test_api 他不能改吧? 10/01 10:24
→ Lipraxde: 把 B_API 改成 static 出錯的地方也怪怪的 @@ 10/01 10:25
推 sighAll: 謝謝! 10/21 22:48