經(jīng)常會有一些類庫或者API要求傳入一個(gè)等效于全局函數(shù)的函數(shù)指針作為回調(diào)函數(shù),一個(gè)典型的例子是Win32的建立線程
DWORD WINAPI ThreadFunc(LPVOID lpParameter);
HANDLE hThread = CreateThread(NULL, NULL, ThreadFunc, NULL, NULL, NULL);
然而,對于我們自己的工程來說,更希望作為線程的函數(shù)是某個(gè)類的成員函數(shù),所以需要在這個(gè)全局函數(shù)里調(diào)用類的成員函數(shù),像這樣
ClassA a;
DWORD WINAPI ThreadFunc(LPVOID lpParameter)


{
return ((ClassA*) lpParameter)->SomeMethod();
}

HANDLE hThread = CreateThread(NULL, NULL, ThreadFunc, &a, NULL, NULL);
DirectX SDK以前就用過這樣的方法,也可以把全局函數(shù)換成類的靜態(tài)成員函數(shù),
但這樣用起來很麻煩,每次都要寫一個(gè)全局函數(shù)的Shell,所以這里,我們想辦法把這個(gè)過程自動化起來.
問題的關(guān)鍵是在靜態(tài)或者全局的函數(shù)里,只能得到一個(gè)傳進(jìn)來的參數(shù),而要指定一個(gè)成員函數(shù),需要一個(gè)this指針,以及一個(gè)指向類成員函數(shù)的指針,這兩個(gè)參數(shù)沒法全部通過lpParameter傳進(jìn)來,除非lpParameter傳一個(gè)額外寫的結(jié)構(gòu)的指針,這個(gè)結(jié)構(gòu)里包含this指針和成員函數(shù)指針,但這樣需要臨時(shí)分配一個(gè)對象,不方便,所以只能犧牲運(yùn)行時(shí)代碼的簡潔性,用模板參數(shù)來傳成員函數(shù)指針的值,而lpParameter只負(fù)責(zé)傳this,但是另一個(gè)問題是用模板參數(shù)來傳具體的值時(shí),必須類型已知,像下面的代碼是不能運(yùn)作的
template<typename T, PtrToMemThreadFun pFunc>
DWORD WINAPI ThreadFunc(LPVOID lpParameter)


{
return (((T*)lpParameter)->*pFunc)();
}

CreateThread(NULL, NULL, ThreadFunc<ClassA, &ClassA::SomeMethod>, &a, NULL, NULL);
因?yàn)镻trToMemThreadFun的類型不定,所以只能先外包一層模板類來確定類型,像這樣
template<typename T>
struct ThreadFac


{
typedef DWORD (T::*PtrToMemThreadFunc)();
typedef T ClassType;

template<PtrToMemThreadFunc pFunc>
static DWORD WINAPI ThreadFunc(LPVOID lpParameter)

{
return (((ClassType*)lpParameter)->*pFunc)();
}
};

調(diào)用時(shí),就可以自動化了
// Globally
CreateThread(NULL, NULL, ThreadFac<ClassA>::ThreadFunc<&ClassA::SomeMethod>, &a, NULL, NULL);

// In methods of ClassA
CreateThread(NULL, NULL, ThreadFac<ClassA>::ThreadFunc<&ClassA::SomeMethod>, this, NULL, NULL);

