//This has a large number of steps, but I'm gonna post them all. This is all using native Lua 5 and the lua CAPI.
int CreateInstanceOfT(lua_State* L) {
new (lua_newuserdata(L, sizeof(T))) T(constructor args);
return 1;
}
int CallSomeFuncOnT(lua_State* L) {
if (lua_istable(L, 1)) { // If we're passed a table, get CData
lua_getfield(L, 1, "CData");
lua_replace(L, 1);
}
if (!lua_touserdata(L, 1))
lua_error(L); // longjmp out.
T& ref = *(T*)lua_touserdata(L, 1);
ref.SomeFunc(); // If you want args, I'll assume that you can pass them yourself
return 0;
}
int main() {
lua_State* L = luaL_newstate();
lua_pushcfunction(L, CreateInstanceOfT);
lua_setglobal(L, "CreateInstanceOfT");
lua_pushcfunction(L, CallSomeFuncOnT);
lua_setglobal(L, "CallSomeFuncOnT");
luaL_dofile(L, "something.lua");
lua_close(L);
}
-- Accompanying Lua code: semicolons are optional but I do out of habit. In something.lua
function CreateCInstance()
local Instance = {
CData = CreateInstanceOfT();
SomeFunc = CallSomeFuncOnT;
}
return Instance;
end
local object = CreateCInstance();
object:SomeFunc(); // Calls somefunc.
ho potuto inviare una grande quantità di dettagli su come rendere più facile l'esposizione, e come fare l'ereditarietà, e simili - e avrà bisogno di alterare se si vuole esporre più di un T (credo che il la soluzione più comune è un semplice accordo struct { std::auto_ptr<void>, int type }
). Ma dovrebbe essere un punto di partenza se non capisci nulla di questo processo.
Bascalmente, in primo luogo, chiediamo a Lua di allocare un po 'di spazio (i dati utente), quindi inserire T in esso. Quando viene visualizzato CallSomeFuncOnT, prima chiediamo se abbiamo una tabella (molte classi Lua sono basate su tabelle, poiché supportano l'orientamento degli oggetti, i metacli e così via) e ottengono i dati utente, che poi convertiamo in un puntatore al nostro oggetto, quindi convertirlo in un riferimento. Ricorda che lua_touserdata ti dà un vuoto *, quindi è meglio che tu sia dannatamente sicuro di ciò che è dall'altra parte. Quindi chiamiamo somefunc e ritorniamo. In Main, registriamo semplicemente le funzioni come globali.
Ora, in Lua, quando si chiama CreateInstanceOfT, chiama in modo efficace il costruttore T, in modo trasparente all'utente Lua. Poi lo buttiamo in un tavolo, che è più semplice per i novizi di Lua, e chiamiamo SomeFunc passandogli questa tabella.
Uomo, non posso credere quanto questo codice faccia schifo: P – Puppy
Mi sbaglio, o è vero che il distruttore di T non viene mai chiamato usando questa tecnica? A quanto ho capito, Lua non sa nulla degli oggetti C++ e chiama semplicemente 'free' per la memoria che controlla, come quella allocata da' lua_newuserdata'. –
Abbastanza sicuro di aver lasciato definitivamente quella parte. Probabilmente insieme a molte altre parti utili. – Puppy