经常会有一些类库或者API要求传入一个等效于全局函数的函数指针作为回调函数,一个典型的例子是Win32的建立线程

DWORD WINAPI ThreadFunc(LPVOID lpParameter);
HANDLE hThread 
= CreateThread(NULL, NULL, ThreadFunc, NULL, NULL, NULL);

然而,对于我们自己的工程来说,更希望作为线程的函数是某个类的成员函数,所以需要在这个全局函数里调用类的成员函数,像这样

ClassA a;
DWORD WINAPI ThreadFunc(LPVOID lpParameter)
{
    
return ((ClassA*) lpParameter)->SomeMethod();
}


HANDLE hThread 
= CreateThread(NULL, NULL, ThreadFunc, &a, NULL, NULL);

DirectX SDK以前就用过这样的方法,也可以把全局函数换成类的静态成员函数,

但这样用起来很麻烦,每次都要写一个全局函数的Shell,所以这里,我们想办法把这个过程自动化起来.

问题的关键是在静态或者全局的函数里,只能得到一个传进来的参数,而要指定一个成员函数,需要一个this指针,以及一个指向类成员函数的指针,这两个参数没法全部通过lpParameter传进来,除非lpParameter传一个额外写的结构的指针,这个结构里包含this指针和成员函数指针,但这样需要临时分配一个对象,不方便,所以只能牺牲运行时代码的简洁性,用模板参数来传成员函数指针的值,而lpParameter只负责传this,但是另一个问题是用模板参数来传具体的值时,必须类型已知,像下面的代码是不能运作的

template<typename T, PtrToMemThreadFun pFunc>
DWORD WINAPI ThreadFunc(LPVOID lpParameter)
{
    
return (((T*)lpParameter)->*pFunc)();
}


CreateThread(NULL, NULL, ThreadFunc
<ClassA, &ClassA::SomeMethod>&a, NULL, NULL);

因为PtrToMemThreadFun的类型不定,所以只能先外包一层模板类来确定类型,像这样

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)();
    }

}
;

调用时,就可以自动化了

// 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);