メンバ関数の呼び出し規約

なんとなくC++のメンバ関数の呼び出し規約を調べてみたという件。
VC++2005以降では__thiscallという名前がついていることを知った。


で、もしかして__cdeclつけたら、_beginthread()の引数にもできるのか?と思ったらできた。(VC6/2005で確認)

#include <Windows.h>
#include <Process.h>
#include <iostream>

struct A {
    void __cdecl Self(void) { std::cout << "this: " << this << std::endl; }
};

int main(int argc, char *argv[])
{
    A a;

    a.Self();  // 普通に呼び出し
    void (__cdecl A::*Self)(void) = &A::Self;  // 直接キャストできないので変数にコピーしておく
    _beginthread((void (*)(void *))*(void **)&Self, 0, &a);  // 引数としてthisを渡す

    Sleep(1000);
    return 0;
}

この方法だとthisが(ecxではなく)スタックに積まれる。staticメンバ関数を介さずに呼び出すことができるので、staticメンバ関数の名前について悩んだり議論したりする手間が省ける。
thisをvoid *にキャストしているのでthisポインタのサイズがvoid *と異なる場合には問題だが、それはstaticメンバ関数を使う場合でも同じではある。