2017-08-20 101 views
1

我有一個Lua功能註冊一個希望將元表作爲參數和我要修改的表的內容中C++運行:傳遞參數作爲參考從Lua到C++

int operate(lua_State *L) 
{ 
    std::vector<int> values{}; 

    if (auto length = get_length_at_index(L, 1)) 
    { 
     result.reserve(length); 

     lua_pushnil(L); 
     while (lua_next(L, 1)) 
     { 
      result.push_back(lua_tointeger(L, -1)); 
      lua_pop(L, 1); 
     } 
    } 

    for (auto &v : values) 
    { 
     v *= 2; 
    } 

    return 0; 
} 

int main() 
{ 
    auto L = luaL_newstate(); 

    luaL_dofile(L, "script.lua"); 
    lua_register(L, "operate", operate); 

    return 0; 
} 

上述代碼讀取"lua.script",其看起來像這樣:

values = {1, 2, 3, 4, 5, 6} 
operate(values) 

for index = 1, #values do 
    print(values[index]) 
end 

預期的輸出是從1到6乘以2的值,但輸出是未修改的值。很明顯,這是因爲我複製 metatable到std::vector並修改副本。

有過的Lua的方式,它們反映在C++應用更改對象從C++運行時操作的方法嗎? PS:我知道我可以返回表作爲函數的返回值,但我想知道是否還有其他選項。回到頂端這篇文章中的信息適用於:

+0

在任何情況下,您必須在加載使用它的腳本之前在解釋器中註冊該函數。如果沒有'luaL_openlibs(L)',你將無法'打印'。 –

回答

2

編輯:我沒有看到你已經知道這是爲什麼。對於未來的讀者來說,解釋已經轉移到了底部。

第一循環之後,你的表保持在堆棧的頂部,簡化了以下解決方案。與替換您第二循環:

int count = int(result.size()); 
for (int i = 0; i < count; ++i) { 
    lua_pushinteger(L, result[i] * 2); 
    lua_rawseti(L, -2, i); 
} 

-2是指下面的堆棧的頂部的LUA值(類似地,-1指的是頂部)。當達到rawseti您的LUA棧看起來像:

[-1]:副本result[i]
[-2]:你values

rawseti彈出值出棧,並將其存儲的頂部在指定的表和索引中,使表再次成爲堆棧的頂部。

注意,你其實可以做到這一點在第一循​​環中,但是你應該避免的一種習慣,因爲一些LUA操作引起,而迭代不確定的行爲,並且它的代碼進一步複雜化。澄清請參閱this post

這是爲什麼發生?

綜上所述,代碼寫入到C++存儲器,但不是LUA表。

第一循環迭代,讀取每個值,並將其添加到result容器。

lua_pushnil(L); 
while (lua_next(L, 1)) 
{ 
    result.push_back(lua_tointeger(L, -1)); 
    lua_pop(L, 1); 
} 

第二回路加倍C++容器內的每個元素的值。

for (auto &v : values) 
{ 
    v *= 2; 
} 
0

您無法獲得對Lua堆棧上的值的引用。但是你可以在原地修改表格。

#include <cassert> 
#include <lua.hpp> 

int operate(lua_State *L) 
{ 
    assert(lua_istable(L,1)); 

    int const N = lua_rawlen(L,1); 

    for (int i = 1; i <= N; ++i) 
    { 
    lua_pushinteger(L, i); 
    lua_gettable(L,1); 
    int value = lua_tonumber(L,-1); 

    value *= 2; 

    lua_pushinteger(L, i); 
    lua_pushinteger(L, value); 
    lua_settable(L,1); 
    } 

    return 0; 
} 

int main() 
{ 
    auto L = luaL_newstate(); 
    luaL_openlibs(L); 

    lua_register(L, "operate", operate); 
    luaL_dofile(L, "script.lua"); 
} 
1

由於傳遞給函數的參數被複制到被調用棧,所以只有傳遞的表(和userdata)才能被突變。因爲在你的函數中是這樣的,所以可以創建一個表包裝類,它可以將[]重載到lua_gettable()/ lua_settable(),但它可能不值得,更像C++問題。

另請參見https://github.com/ThePhD/sol2/more那樣。與大多數C++模板一樣,很難快速判斷sol2是否可以執行t[i] *= 2,所以ymmw。