2010-04-05 6 views
7

1 클래스의 1 메서드가 자주 변경되는 C++ 프로젝트가 있습니다. 그래서 저는 C++에서 루아로 그 코드를 가져 가고 싶습니다. 참고, 나는 루아에 초보자입니다.루아 함수에 C++ 객체 전달

전체 작업 :

  1. 바인드 루아 상태 머신에 몇 가지 클래스 메소드;
  2. 클래스 객체에 대한 참조를 Lua로 작성된 함수로 전달합니다.
  3. 루아 함수에서 전달 된 C++ 객체와 작동합니다.

나는 Lunar로 첫 단계를 만드는 방법을 찾았으며 두 번째와 세 번째를 감당할 수 없습니다.

SWIG 및 부스트 기능을 사용할 수 없습니다.

답변

7
//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. 

내가 노출이 용이하게하고, 상속을 만드는 방법, 그리고 그와 같은 방법에 대한 세부 사항의 다량 게시 할 수 - 당신은 하나 이상의 T를 노출 할 경우이 변경 필요합니다을 (내가 생각 가장 일반적인 솔루션은 간단한 struct { std::auto_ptr<void>, int type } 거래입니다. 그러나이 과정에 대해 이해하지 못한다면 출발점이되어야합니다.

Bascally, 먼저 Lua에 약간의 공간 (userdata)을 할당 한 다음 T를 넣으라고합니다. CallSomeFuncOnT가 생기면 먼저 테이블을 가지고 있는지 물어 봅니다 (루아 클래스는 테이블을 기반으로합니다. 객체 지향, 메타 테이블 등을 지원하기 때문에 테이블을 기반으로합니다). 그리고 userdata를 가져 와서 우리의 포인터로 변환합니다. 개체로 변환 한 다음 참조로 변환합니다. lua_touserdata는 무효 *를 제공한다는 것을 기억하십시오. 그래서 상대방의 상황에 대해 확신 할 수 있습니다. 그런 다음 somefunc를 호출하고 리턴합니다. Main에서는 함수를 전역 변수로 등록하면됩니다.

이제 Lua에서 CreateInstanceOfT를 호출하면 Lua 사용자에게 투명하게 T 생성자가 호출됩니다. 그런 다음 루아 초보자에게는 더 간단하게 테이블에 놓고 SomeFunc를 호출하여이 테이블을 전달합니다.

+1

남자, 나는이 코드가 얼마나 짜증나는지 믿을 수 없다 : P – Puppy

+0

나는 틀린가, 아니면 T의 소멸자가 결코이 기술을 사용하여 호출되지 않는다는 사실인가? 내가 이해하는 것처럼, 루아는 C++ 객체에 대해 아무것도 모르고'lua_newuserdata '에 의해 할당 된 것과 같이 단순히 제어하는 ​​메모리에'free'를 호출합니다. –

+0

나는 분명히 그 부분을 분명히 남겨 두었습니다. 아마 다른 많은 유용한 부분과 함께. – Puppy

1

luabind을 보셨습니까? LUA에 C++ 객체와 함수를 공개하는 것이 상당히 쉽습니다.

+0

예, 있습니다. http://www.rasterbar.com/products/luabind/docs.html에서 언급했듯이 부스트는 – peterdemin

0

John과 마찬가지로 luabind을 사용하고 추천했습니다. 그러나 부스트를 사용하는 것이 옵션이 아니므로 list of libraries on this page이 도움이 될 수 있습니다. DoItYourselfCppBinding page on the lua-users wiki을 확인할 수도 있습니다.

페이지에서 언급 된 하나의 라이브러리는 종속성이없는 oolua입니다 (그래서).

+0

을 사용합니다. 나는 쉬운 작동을 위해 라이브러리가 필요하다고 믿을 수 없습니다. – peterdemin

+0

언제든지 Lua C API를 사용하고 바인딩을 직접 처리 할 수 ​​있습니다. 라이브러리는 C++ 클래스를 Lua에 바인딩하는 것이 "더 쉽다"도록하기 위해 존재합니다. –

+0

Zack의 진술은 정확합니다. OOLua는 루아에만 필요합니다. – user244655