C++インスタンス関数を呼び出すSquirrelインスタンス関数(マイフェイバリットな)

SQPlusはC++インスタンスをinstanceupへ、関数ポインタをfunctionのfree variableへいれてる。free variable分はいらなくないか?と思ったので。自分はこんなふうに書いた。テンプレートってホント融通きくなあ。

inline static void mysq_register_function(HSQUIRRELVM v, const char* name, SQFUNCTION func, int numparams, const char* paramtype, SQBool bstatic = SQFalse)
{
	sq_pushstring(v,name,-1);
	sq_newclosure(v,func,0);
	if(paramtype) sq_setparamscheck(v,numparams,paramtype);
	sq_setnativeclosurename(v,-1,name);
	sq_newslot(v,-3,bstatic);
}

template <typename T, int(T::*FUNC)(HSQUIRRELVM)>
static int _mysq_instance_nativeclosure(HSQUIRRELVM v)
{
	T* g = (T*)_instance(stack_get(v,1))->_userpointer;
	return (g->*FUNC)(v);
}

#define MYSQ_REG_INSTANCE_LINKED_FUNCTION(VM,CLASS,FUNCNAME,PNUM,FORMAT) \
	mysq_register_function(VM,#FUNCNAME,_mysq_instance_nativeclosure<CLASS,&CLASS::FUNCNAME>,PNUM,FORMAT)

で、こんな風に使える。

SQObjectPtr sqclass;
_table(v->_roottable)->Get(SQObjectPtr(SQString::Create(_ss(v),"Agent")),sqclass);
sq_pushobject(v,sqclass);
MYSQ_REG_INSTANCE_LINKED_FUNCTION(v,MobBotWithAI,WalkTo, 2, ".x");
MYSQ_REG_INSTANCE_LINKED_FUNCTION(v,MobBotWithAI,Attack, 0, ".ix");
MYSQ_REG_INSTANCE_LINKED_FUNCTION(v,MobBotWithAI,Track, 2, ".x");
sq_poptop(v);

Squirrelインスタンスをつくるときは紐付けるC++インスタンスをsq_setinstanceupすることを忘れずに

mysq_call(v,true,-1,"Agent");
m_sqagent = stack_get(v,-1); // C++ -> Squirrel の参照
_instance(m_sqagent)->_userpointer = this; // C++ <- Squirrel の参照

最近はできるだけスタックを使わないのがマイブーム。