2012-06-19 10 views
9

estoy envolviendo una función C con Lua, mediante la API de Lua-C para Lua 5.2:¿Cómo creo un objeto de clase en Lua-C API 5.2?

#include <lua.h> 
#include <lauxlib.h> 
#include <stdlib.h> 
#include <stdio.h> 

int foo_gc(); 
int foo_index(); 
int foo_newindex(); 
int foo_dosomething(); 
int foo_new(); 

struct foo { 
    int x; 
}; 

static const luaL_Reg _meta[] = { 
    {"__gc", foo_gc}, 
    {"__index", foo_index}, 
    {"__newindex", foo_newindex}, 
    { NULL, NULL } 
}; 
static const luaL_Reg _methods[] = { 
    {"new", foo_new}, 
    {"dosomething", foo_dosomething}, 
    { NULL, NULL } 
}; 

int foo_gc(lua_State* L) { 
    printf("## __gc\n"); 
    return 0; 
} 
int foo_newindex(lua_State* L) { 
    printf("## __newindex\n"); 
    return 0; 
} 
int foo_index(lua_State* L) { 
    printf("## __index\n"); 
    return 0; 
} 
int foo_dosomething(lua_State* L) { 
    printf("## dosomething\n"); 
    return 0; 
} 
int foo_new(lua_State* L) { 
    printf("## new\n"); 

    lua_newuserdata(L,sizeof(Foo)); 
    luaL_getmetatable(L, "Foo"); 
    lua_setmetatable(L, -2); 

    return 1; 
} 

void register_foo_class(lua_State* L) { 
    luaL_newlib(L, _methods); 
    luaL_newmetatable(L, "Foo"); 
    luaL_setfuncs(L, _meta, 0); 
    lua_setmetatable(L, -2); 
    lua_setglobal(L, "Foo"); 
} 

Cuando ejecuto este Lua:

local foo = Foo.new() 
foo:dosomething() 

... Veo esta salida (con error):

## new 
## __index 
Failed to run script: script.lua:2: attempt to call method 'dosomething' (a nil value) 

¿Qué estoy haciendo mal? Gracias

+0

Pruebe 'for k, v en pares (getmetatable (foo)) do print (k, v) end'. – lhf

+2

En Lua 5.2, puede usar 'luaL_setmetatable (L," Foo ")' en lugar de 'luaL_getmetatable (L," Foo "); lua_setmetatable (L, -2); ' – lhf

+1

OT: No debe usar' __' en los identificadores en C. – u0b34a0f6ae

Respuesta

8

Ok, lo tengo funcionando. He tenido que añadir __index y __metatable de nuevo metatabla Foo 's, como se muestra a continuación:

void register_foo_class(lua_State* L) { 
    int lib_id, meta_id; 

    /* newclass = {} */ 
    lua_createtable(L, 0, 0); 
    lib_id = lua_gettop(L); 

    /* metatable = {} */ 
    luaL_newmetatable(L, "Foo"); 
    meta_id = lua_gettop(L); 
    luaL_setfuncs(L, _meta, 0); 

    /* metatable.__index = _methods */ 
    luaL_newlib(L, _methods); 
    lua_setfield(L, meta_id, "__index");  

    /* metatable.__metatable = _meta */ 
    luaL_newlib(L, _meta); 
    lua_setfield(L, meta_id, "__metatable"); 

    /* class.__metatable = metatable */ 
    lua_setmetatable(L, lib_id); 

    /* _G["Foo"] = newclass */ 
    lua_setglobal(L, "Foo"); 
} 
3

Traté de responder a su solución, pero al parecer no tengo la reputación de hacerlo, sin embargo, así que aquí va una por separado responder.

Su solución es bastante agradable, pero no permite algo que me gustaría hacer: tener acceso "tipo array" a un objeto y aún tener funciones en él. Echar un vistazo a este código Lua:

Foo = {} 

mt = { 
__index = function(table, key) 
    print("Accessing array index ", tostring(key), "\n") 
    return 42 
end 
} 
setmetatable(Foo, mt) 

Foo.bar = function() 
    return 43 
end 

print(tostring(Foo[13]), "\n") 
print(tostring(Foo.bar()), "\n") 

--[[ 
Output: 
Accessing array index 13 
42 
43 
]]-- 

Registro de una clase utilizando su solución no parece permitir esto, como la entrada __index se sobrescribe. Puede que no tenga sentido tener acceso de matriz y acceso a función en una clase, pero por simplicidad (ofreciendo una función C para registrar ambos tipos de clases) me gustaría usar el mismo código en todas partes. ¿Alguien tiene una idea de cómo se puede eludir esta restricción, de modo que pueda crear una clase desde C que tenga tanto una función Foo.bar() como también Foo [13]?

Cuestiones relacionadas