luabind:如何通过引用将值从C++传递给lua函数

luabind: How to pass value from C++ to lua function by reference?

本文关键字:C++ 函数 lua 何通过 引用 luabind      更新时间:2023-10-16

在C++上编程时,可以执行以下操作:

void byReference(int &y)
{
    y = 5;
}
int main()
{
   int x = 2;      // x = 2
   byReference(x); // x = 5
}

如何使用luabind进行同样的操作?

Luabind医生说:

如果要将参数作为引用传递,则必须对其进行包装与CCD_ 1。

像这样:

int ret = call_function(L, "fun", boost::ref(val));

但当我尝试这样做时:

#include <iostream>
#include <conio.h>
extern "C" 
{
    #include "lua.h"
    #include "lualib.h"
    #include "lauxlib.h"
}
#include <luabindluabind.hpp>
using namespace std;
using namespace luabind;
int main() 
{
  lua_State *myLuaState = luaL_newstate();
  open(myLuaState);
  int x = 2;
  do
  {
    luaL_dofile(myLuaState, "script.lua");
    cout<<"x before = "<< x <<endl;
    call_function<void>(myLuaState, "test", boost::ref(x));
    cout<<"x after = "<< x <<endl;
  } while(_getch() != 27);
  lua_close(myLuaState);
}

script.loa

function test(x)
    x = 7
end

我的程序在运行时崩溃,出现以下错误:

LuaScripting.exe0x76B5C42D处的未处理异常:MicrosoftC++异常:内存位置0x0017F61C处的std::runtime_error

那么,如何通过引用将值从C++传递到lua函数,这样我就可以在脚本中更改它,它也会在C++程序中更改?我使用的是boost 1.55.0,lua 5.1,luabind 0.9.1

编辑:

当我尝试捕获时

try {
call_function<void>(myLuaState, "test", boost::ref(x));
}catch(const std::exception &TheError) {
cerr << TheError.what() << endl;

它给了我一个"Trying to use unregistered class"错误。

编辑2:

经过一点研究,我发现"Trying to use unregistered class"的错误抛出是因为boost::ref(x)。我注册了一个int&类(只是猜测(:

  module(myLuaState)
      [
          class_<int&>("int&")
      ];

CCD_ 10错误消失。但是在Boost.Ref2中调用print(x)仍然会导致"lua runtime error",并且程序仍然不能执行我想从中执行的操作。

我已经设法让这件事成功了。嗯,与问题中的不完全一样:我传递了自定义类型GameObject,而不是int

但由于某些原因,我仍然无法使它与intfloat等简单类型一起工作。

所以,首先我决定自己构建luabid和lua,只是为了确保它们能在VS2012中工作。我遵循了这个问题的指示。

然后我写了这个测试程序:

#include <iostream>
#include <conio.h>
extern "C" 
{
    #include "lua.h"
    #include "lualib.h"
    #include "lauxlib.h"
}
#include <luabindluabind.hpp>
#include <luabindadopt_policy.hpp>
using namespace std;
using namespace luabind;
struct Vector2
{
    float x, y;
};
class Transform
{
public:
    Transform()
    {
        pos.x = 0;
        pos.y = 0;
    }
public:
    Vector2 pos;
};
class Movement
{
public:
    Movement(){}
public:
    Vector2 vel;
};
class GameObject
{
public:
    GameObject(){}
    Transform& getTransform()
    {
        return _transform;
    }
    Movement& getMovement()
    {
        return _movement;
    }
private:
    Transform _transform;
    Movement  _movement;
};
int main()
{
    lua_State *myLuaState = luaL_newstate();
    open(myLuaState);
    module(myLuaState) [
      class_<Vector2>("Vector2")
          .def(constructor<>())
          .def_readwrite("x", &Vector2::x)
          .def_readwrite("y", &Vector2::y),
      class_<Transform>("Transform")
          .def(constructor<>())
          .def_readwrite("pos", &Transform::pos),
      class_<Movement>("Movement")
          .def(constructor<>())
          .def_readwrite("vel", &Movement::vel),
      class_<GameObject>("GameObject")
          .def(constructor<>())
          .def("getTransform", &GameObject::getTransform)
          .def("getMovement", &GameObject::getMovement)
    ];
    GameObject _testGO;
    _testGO.getMovement().vel.x = 2;
    _testGO.getMovement().vel.y = 3;
    do
    {
        cout<<"_testGO.pos.x before = "<< _testGO.getTransform().pos.x <<endl;
        cout<<"_testGO.pos.y before = "<< _testGO.getTransform().pos.y <<endl;
        try 
        {
            luaL_dofile(myLuaState, "script.lua");
            call_function<void>(myLuaState, "testParams", boost::ref(_testGO), 0.3);
        }
        catch(const exception &TheError)
        {
            cerr << TheError.what() << endl;
        }
        cout<<"_testGO.pos.x after = "<< _testGO.getTransform().pos.x <<endl;
        cout<<"_testGO.pos.y after = "<< _testGO.getTransform().pos.y <<endl;
    }
    while(_getch() != 27);
    lua_close(myLuaState);
    return 0;
}

script.loa:

function testParams(owner, dt)
    owner:getTransform().pos.x = owner:getMovement().vel.x * dt;
    owner:getTransform().pos.y = owner:getMovement().vel.y * dt;
end

它奏效了:

_testGO.pos.x before = 0
_testGO.pos.y before = 0
_testGO.pos.x after = 0.6
_testGO.pos.y after = 0.9

将尝试找出如何管理简单类型。

更新:

这是同一个问题的答案,我上了luabind邮件列表:

‘不可能通过引用传递在lua中用内置类型建模的对象类型。在Lua中,不存在引用或值类型等类型的属性。类型可以是引用类型(表(,也可以是值类型(数字等内置类型(。但是,您可以在lua端返回新值。可以建立一个策略,将引用积分类型转换为已解析的返回类型列表,因此它在c++方面是透明的。不过,这将对卢阿方面施加严格限制链接:http://sourceforge.net/p/luabind/mailman/message/32692053/

在lua中,如果你想模拟引用一个变量/表,你会将其声明为全局的,然后在函数中使用它。

-- global table t
t = {}
-- insert the value of val into t by index or by property
-- aGenericFunction1(val[, property])
function aGenericFunction1(val, property)
   if property then
       t[property] = val
   else
       table.insert(t, val)
   end
end

这不是完全一样的事情,但这是一个简单的解决方案。

现在,每次调用aGenericFunction1时,它都会按属性或索引更新t表。

Example:
    aGenericFunction1("Barks!", "dog")
    print(t.dog)
    -- prints Barks!

同样的事情可以对变量完成。。。

-- global variable x
x = 0
-- insert the value of val into x
function aGenericFunction2(val)
   x = val
end

同样的事情,每次你调用aGenericFunction2,它都会覆盖x

 Example:
     aGenericFunction2(4)
     print(x)
     -- prints 4

因此,从本质上讲,t或x将成为参考,这取决于你想要实现的目标。:(