【问题标题】:How to bind C++ public variable for access in lua script如何绑定 C++ 公共变量以在 lua 脚本中访问
【发布时间】:2014-03-28 21:06:38
【问题描述】:

如何从 Lua 脚本中的一个类访问变量。 下面是一个例子:

// C++
struct HObject{
    float x, y, z;
    float sx, sy, sz;

    void funcTest(void);
}

// Binding OBject
static bool checkFunctionArgs(lua_State* ls, const char* fname, unsigned int nargs)
{
   // etc
}

HObject* HObject_check(lua_State* ls, int index)
{
    // etc
}

static int HObject_newHObject(lua_State* ls)
{
   // etc
}

static int HObject_destructor(lua_State* ls)
{
   // etc
}

void HTest_register(lua_State* ls)
{
   // etc
}

-- Lua script
local obj = HObject:new() -- Create instance
obj:funcTest() -- OK
obj.x = 10 -- How to bind?
io.write(obj.x) -- How to bind?

我已经链接了类的函数,缺少变量。

对不起英文...

【问题讨论】:

  • 你试过什么?解决此类问题的一个好技巧是使用绑定生成器(如 SWIG,来自 swig.org)并查看它为您尝试执行的任何操作生成了哪些代码。或者直接使用绑定库(SWIG、luabind 等)为自己省去很多麻烦 :)
  • @Schollii 我需要提供速度的库。 Luabind 和其他人的性能略低。我目前正在使用 Luajit。我用 Luabind 测试过它更容易。但是速度不一样。
  • 那是为了优化发布版本?使用相同的错误检查?执行时间有什么区别?

标签: c++ c attributes lua bind


【解决方案1】:

您想要做的事情可以通过 PIL 中描述的 userdata 机制来完成,从 http://www.lua.org/pil/28.html 开始。你已经知道这件事了吗?你在 obj:FuncTest() 旁边写了“Okay”,就好像你已经让那部分工作了一样。

我会从那个页面给出一些很好的例子。他们描述了如何创建类似的 C 结构

typedef struct NumArray {
  int size;
  double values[1];  /* variable part */
} NumArray;

然后通过在库中注册方法

static const struct luaL_reg arraylib [] = {
  {"new", newarray},
  {"set", setarray},
  {"get", getarray},
  {"size", getsize},
  {NULL, NULL}
};

int luaopen_array (lua_State *L) {
  luaL_openlib(L, "array", arraylib, 0);
  return 1;
}

可以向用户数据添加数据和方法,并从 Lua 访问它们。下面是使用数组运算符 [],这需要更多的工作,但他们展示了如何做到这一点。

a = array.new(1000)
a[10] = 3.4         -- setarray
print(a[10])        -- getarray   --> 3.4

现在我并不肯定,但我想由于 userdata 是一个 C 结构,它不能有函数,而只有函数指针。因此,在 C 中,您可能必须将“a”的适当成员传递给函数。

【讨论】:

  • 感谢您的回答。所以我知道如何绑定函数。问题是我不想使用 MyClass: MyClass 和 setMyVariable: getMyRariable 方法。我想使用 MyClass.myVariable 或 = 10 打印 (MyClass.myVariable)。
  • 我不认为这会支持s = a.size:如果你print(type(s)) 它会说功能,不是吗?
  • 是的,你是对的,他们显示的代码不会让你像 s = a.size 那样访问它并获得一个数字。
【解决方案2】:

我从我们的项目中找到了一个可以满足您需求的示例。

typedef int (*getSetFunction) (lua_State*);

typedef struct luaMyValReg {
  const char *name;
  getSetFunction getter;
  getSetFunction setter;
} luaMyValReg;

#define luaL_reg luaL_Reg

typedef struct luaMyTable {
luaL_reg    *functions;
luaL_reg    *methods;
luaMyValReg *values;
luaMyValReg *arrays;
luaL_reg    *array_methods;
} luaMyTable;

static const struct luaMyValReg lib_val[] = {
   { "key1", MyClass::l_getKey1, MyClass::l_setKey1},
 ...
    {NULL, NULL, NULL}
 }

这些被设置到一个结构中并传递给一个将设置用户数据的函数。

table.functions = (luaL_reg *) &lib_f;
table.methods = (luaL_reg *) &lib_m;
table.values = (luaMyValReg *) &lib_val;
MyClass::initTable(&table, REGNAME, REGID, ARRAY_REGID);

在该函数中,有一个位创建元表,并将每个字段添加到 lib_val 数组中。 LGlobalState 是 lua_State* 指针。

// Register the functions for the Table
luaL_register(LGlobalState, regname, table->functions);

// Stk: Table
// Create the metatable
luaL_newmetatable(LGlobalState, regid);

// Stk: Table metatable
// Register its methods, leaves it on top of the stack
luaL_register(LGlobalState, NULL, table->methods);

// Stk: Table metatable
// Set the metatable
lua_setmetatable(LGlobalState,-2);

// Stk: Table
// Push metatable
lua_getmetatable(LGlobalState, -1);
// Stk: Table metatable

// Add fields to the metatable
int i = 0;
while (table->values[i].name != NULL)
{
    addMetaField(LGlobalState, table->values[i].name, i);
    i++;
}

// Stk: Table, metatable
lua_pop(LGlobalState, 2);
// Stk: empty

if (lua_gettop(LGlobalState) > 0)
    tngL_error(LGlobalState, "%s inconsistant stack size\n", regname);

这是添加值的函数。

////////////////////////////////////////////////////////////////////////////////
int LUATask::addMetaField(lua_State *L, const char *pKey, int nIndex)
////////////////////////////////////////////////////////////////////////////////
//  Add a field to the metatable.  It must already be on the top
//  of the stack
{
// Stk: metatable
lua_pushstring(L, pKey);
lua_pushnumber(L, nIndex);
// Stk: metatable, string, number
// Use lua_rawset() instead of lua_settable() to avoid
// the __newindex call
lua_rawset(L, -3);
// Stk: metatable
return 1;
}

【讨论】:

  • 感谢您的回答。我无法解决此错误。错误:非静态成员函数'int HObject::getId()'的使用无效。
  • 这可能与您的课程是否为静态有关。我明天检查。 stackoverflow.com/questions/17391853/…
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-05-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多