When programming on C++, you can do the following:
void byReference(int &y)
{
y = 5;
}
int main()
{
int x = 2; // x = 2
byReference(x); // x = 5
}
How to do the same using luabind?
Luabind docs says:
If you want to pass a parameter as a reference, you have to wrap it with the
Boost.Ref
.Like this:
int ret = call_function(L, "fun", boost::ref(val));
But when I'm trying to do this:
#include <iostream>
#include <conio.h>
extern "C"
{
#include "lua.h"
#include "lualib.h"
#include "lauxlib.h"
}
#include <luabind\luabind.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.lua
function test(x)
x = 7
end
My program crashes at runtime with the following error:
Unhandled exception at at
0x76B5C42D
inLuaScripting.exe
: Microsoft C++ exception:std::runtime_error
at memory location0x0017F61C
.
So, how to pass value from C++ to lua function by reference, so I can change it inside the script and it will be changed in c++ program too? I'm using boost 1.55.0, lua 5.1, luabind 0.9.1
EDIT :
When I try-catched
try {
call_function<void>(myLuaState, "test", boost::ref(x));
}catch(const std::exception &TheError) {
cerr << TheError.what() << endl;
it gave me a "Trying to use unregistered class"
error.
EDIT 2 :
After a little research, I found that "Trying to use unregistered class"
error throwing because of boost::ref(x)
. I registered a int&
class(just a guess):
module(myLuaState)
[
class_<int&>("int&")
];
and "Trying to use unregistered class"
error disappeared. But calling print(x)
in test()
still causes "lua runtime error"
, and program still not doing what I want from it to do.
I've managed to make this thing work. Well, not exactly like in the question: instead of int
I passed my custom type GameObject
.
But for some reason I still can't make it work with simple types like int
, float
etc.
So, first I decided to build luabind and lua by myself, just to be sure that they will work in VS2012. I followed the instructions from this question.
Then I wrote this test program:
#include <iostream>
#include <conio.h>
extern "C"
{
#include "lua.h"
#include "lualib.h"
#include "lauxlib.h"
}
#include <luabind\luabind.hpp>
#include <luabind\adopt_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.lua:
function testParams(owner, dt)
owner:getTransform().pos.x = owner:getMovement().vel.x * dt;
owner:getTransform().pos.y = owner:getMovement().vel.y * dt;
end
And it worked:
_testGO.pos.x before = 0
_testGO.pos.y before = 0
_testGO.pos.x after = 0.6
_testGO.pos.y after = 0.9
Will try to figure out how to manage simple types.
UPDATE:
This is the answer for the same question, I got on the luabind mailing lists:
'It is impossible to pass object types that are modelled in lua with built-in types by reference. In Lua, there exists no attribute to types like reference or value type. A type is either a reference type (tables), or a value type (built-in types like number). What you can do however is return the new value in the lua-side. A policy could be established, that transforms reference integral types to a list of parsed return types, so it is transparent on the c++ side. That would place hard constraints on the lua side though.' link: http://sourceforge.net/p/luabind/mailman/message/32692053/