2016-08-22 1 views
2

내가 가지고이 사람의 문제 : 대신 weren 히 내 다른 방법의 내 유저 데이터의 메타 테이블의 __index을 설정할 때, 그것은 항상 게터라는 것을 특징으로 Lua userdata array access and methods루아 유저 데이터 : 동시 배열 액세스 및 방법이 없습니다

, 메타 이벤트를 선언했다. 위의 링크에 대한 해결책은 루아이며, 나는 비효율적 인 C 구현을 시도했지만 관계없이 새로운 메소드가 더 이상 인수를 취할 수 없다는 새로운 문제가 발생하고 다음과 같은 오류가 발생합니다.

attempt to call method 'asTable' (a table value)

//Methods, many of which are overridden Lua meta-events (with the underscores) 
static const struct luaL_reg vallib_m [] = { 
    {"asTable", PushLuaTable}, //these functions are not called 
    {"asCopy", CopyLuaVal}, 

    {"__newindex", SetLuaVal}, 
    {"__index", GetLuaVal}, 
    {"__tostring", ValToString}, 
    {"__gc", GarbageCollectVal}, 
    {"__metatable", HideMetaTable}, 

    {NULL, NULL} 
}; 

//Static library functions 
static const struct luaL_reg vallib_f [] = { 
    {"specialprint", PrintVals}, 
    {NULL, NULL} 
}; 


int luaopen_custom(lua_State *L) 
{ 
    luaL_newmetatable(L, "custom.Value"); 
    lua_pushstring(L, "__index"); 
    lua_pushvalue(L, -2); /* pushes the metatable */ 
    lua_settable(L, -3); /* metatable.__index = metatable */ 

    luaL_register(L, NULL, vallib_m); 
    luaL_register(L, "special", vallib_f); 

    return 0; 
} 
이 루아 문에

: 나는 모든 것을 설정하는 방법

print_r(c:asTable())

입니다 0

그런 다음 기본적으로 (__index를 통해) 호출되는 getter에서 먼저 호출 할 다른 이벤트를 확인하고 다음과 같이 컨트롤을 전달합니다. 스택의 함수 이름을 포함하는 인수를 제거합니다.

//TODO: this is a tentative fix, I would rather do this with metatables 
//checking for methods 
if (lua_isstring(L, 2)) 
{ 
    field = luaL_checkstring(L, 2); 
    if (unlikely(!field)) 
    { 
     reporter->Warning("Fail in getter -- bad string as method attempt"); 
     return LUA_FAILURE; 
    } 

    if (strcmp(field, "asTable") == 0) 
    { 
     lua_remove(L, 2); //delete string "asTable" 
     return PushLuaTable(L); 
    } 
    else if (strcmp(field, "asCopy") == 0) 
    { 
     lua_remove(L, 2); //delete string "asCopy" 
     return CopyLuaVal(L); 
    } 
    //... other methods. 
    else 
    { 
     //Insert string back into stack?? 
    } 

} 

그것은 상관없이 많은 인수가 전달되는 방법의 함수로 내 방법을 치료하고, 심지어 어떤 괄호 또는 콜론이있는 경우 오류가 발생하지 않습니다. (c.asTable에 의해 접근 할 수 있습니다.이 메소드는 아무런 인자도 필요하지 않지만 메소드를 추가 할 계획입니다. 내 C getter를 통해 이러한 함수를 호출하고 메타 테이블을 사용하여이를 해결하십시오. 가능한 경우 C API를 사용하여 예제를 제공하십시오. 이미 Lua에 StackOverflow 솔루션이 있지만 C로 변환 할 수 없습니다. .

+1

는 [이 않음]의 두 번째 부분을 참조 (http://stackoverflow.com/questions/29957701/how-to-store-a-value-type-in-a-userdata/29967658#29967658). 도움이 – siffiejoe

+0

, 감사 – Leo

+0

약간 복잡하지만 - 그래서 내 경우에는 내가 부를 것이다 moon_propindex (L, vallib_m, setLuaVal?,?)? 좀 더 일반적인 상황에서 정교하게 수 그리고 해결책로 표시됩니다 경우가 좋은 것 – Leo

답변

1

을 당신이 유저 데이터 개체에 대한 액세스를 필요로하기 때문에 당신의 __index 메타 메소드와 같은 기능을해야합니다, 당신이 그것을 __index 경우받지 않습니다 루아에서 C 구조체의 필드에 액세스하는 것은 테이블 :

-- Lua example code; obj* should be userdatas ... 
-- an example __index function 
local function anIndex(o, k) 
    print("accessing", k, "in", o) 
    return 1 
end 

local obj = {} 
local meta = { __index = anIndex } 
setmetatable(obj, meta) 
print(obj) 
--> table: 0xfcb060 
print(obj.x) 
--> accessing x in table: 0xfcb060 
--> 1 

이 속성은 정상적으로 작동하지만 같은 유형의 모든 userdatas가 공유하는 메서드에 액세스하는 것은 불편하고 비효율적입니다.

-- an example method 
local function aMethod(o) 
    print("calling aMethod on", o) 
    return 2 
end 

local obj2 = {} 
local methods = { aMethod = aMethod } 
local meta2 = { __index = methods } 
setmetatable(obj2, meta2) 
print(obj2) 
--> table: 0xfcada0 
print(obj2:aMethod()) 
--> calling aMethod on table: 0xfcada0 
--> 2 

하지만 지금 우리는 모두 원하는 일 : __index 테이블은 더 좋을 것입니다!

메타 메서드는 루아에서 체인 될 수있다, 그래서 우리는 (이 경우 methods)에 __index 테이블에 대한 대체로서 __index 기능 설정을 시도 할 수 있습니다 :

setmetatable(methods, meta) 
print(obj2) 
--> table: 0xfcada0 
print(obj2.x) 
--> accessing x in table: 0xfcade0 
--> 1 
print(obj2:aMethod()) 
--> calling aMethod on table: 0xfcada0 
--> 2 

하지만 가까이 보면, 당신은 볼을 __index 기능 obj2가 아닌 다른 객체 ...

print(methods) 
--> table: 0xfcade0 

를 얻을 수 있음을 대신 첫 번째 인수로 methods 표를 가져옵니다. 따라서 원래의 userdata (이 예제에서는 테이블)에 대한 액세스 권한을 잃어 버리고 실제로 필드를 조회 할 수 없습니다. 그래서 그것은 효과가 없을 것입니다.

setmetatable(methods, nil) -- let's undo this ... 

다행히 __index 기능 (AN upvalue에 저장된 예를 들어, 1) 다른 테이블에 접근을 포함하여 임의의 일을 수행 할 수 있습니다

local obj3 = {} 
local meta3 = { 
    __index = function(o, k) 
    local v = methods[ k ] -- methods is an upvalue here 
    if v == nil then 
     print("accessing", k, "in", o) 
     v = 1 
    end 
    return v 
    end 
} 
setmetatable(obj3, meta3) 
print(obj3) 
--> table: 0xfc23a0 
print(obj3.x) 
--> accessing x in table: 0xfc23a0 
--> 1 
print(obj3:aMethod()) 
--> calling aMethod on table: 0xfc23a0 
--> 2 

지금이 큰 일! 이 문제가 더 자주 발생하면 우리에게 적절한 __index 함수를 만드는 도우미 함수를 작성할 수 있습니다. 인수로 전달 된 indexfunc은 필드 조회에만 관련되며 메소드를 전혀 처리 할 필요가 없습니다. 당신이 루아의 C API에 그 번역하려고하면

local function makeindex(methodstable, indexfunc) 
    return function(o, k) 
    local v = methodstable[ k ] 
    if v == nil then 
     v = indexfunc(o, k) 
    end 
    return v 
    end 
end 

local obj4 = {} 
local meta4 = { __index = makeindex(methods, anIndex) } 
setmetatable(obj4, meta4) 
print(obj4) 
--> table: 0xfc92b0 
print(obj4.x) 
--> accessing x in table: 0xfc92b0 
--> 1 
print(obj4:aMethod()) 
--> calling aMethod on table: 0xfc92b0 
--> 2 

, 당신이 그것을 대신 방법 테이블의 luaL_Reg 배열을하는 것이 더 편리하다고보고, 대신 lua_CFunction 포인터 것이다 : 생성 기능이 있다고 할 것입니다 스택 인덱스를 Lua 함수에 전달한다. 그리고 이것은 moon_propindex() 기능이 this 답변에 연결된 기능입니다 (추가로 luaL_setfuncs()과 같은 모든 방법에 대해 upvalues를 설정합시다).

+0

1K5은 본질적으로 이런 짓을 http://stackoverflow.com/questions/26970316/lua-userdata-array-access-and-methods – Leo

+0

'__index'를 사용하지 못하도록 : 재귀를 방지하기 위해 rawget를 사용하여, 그 번역은 내 문제를 해결 도왔을 제외하고 C 메소드 테이블의 메타 메소드 상속을 위해. 무한 재귀가 발생하면 메서드 테이블에 대한 원시 액세스와 원시 액세스가 아닌 메타 테이블을 설정하는 방법에 버그가 발생합니다. – siffiejoe