我正在使用Luan Pavlik与Lua 5.1的主发行版的luabind 0.9.1,在Win XP SP3上的cygwin +最新补丁x86,增强1.48,gcc 4.3.4.Lua和boost是cygwin预编译的版本.
我已经在静态和共享版本中成功构建了luabind.
两个版本都通过了test_object_identity.cpp测试的所有测试EXCEPT,这两个版本都失败了.
我已经将问题追溯到以下问题:如果为NON内置类创建表中的条目(即,不是int,string等),则无法检索该值.
这是一段代码,演示了这一点:
#include "test.hpp"
#include <luabind/luabind.hpp>
#include <luabind/detail/debug.hpp>
using namespace luabind;
struct test_param
{
int obj;
};
void test_main(lua_State* L)
{
using namespace luabind;
module(L)
[
class_<test_param>("test_param")
.def_readwrite("obj", &test_param::obj)
];
test_param temp_object;
object tabc = newtable(L);
tabc[1] = 10;
tabc[temp_object] = 30;
TEST_CHECK( tabc[1] == 10 ); // passes
TEST_CHECK( tabc[temp_object] == 30 ); // FAILS!!!
}
Run Code Online (Sandbox Code Playgroud)
tabc [1]确实是10而tabc [temp_object]不是30!(实际上,似乎是零)
但是,如果我使用iterate来遍历tabc条目,则有两个条目具有CORRECT键/值对.
有任何想法吗?
BTW,像这样重载==运算符:
#include <luabind/operator.hpp>
struct test_param
{
int obj;
bool operator==(test_param const& rhs) const
{
return obj == rhs.obj;
}
};
Run Code Online (Sandbox Code Playgroud)
和
module(L)
[
class_<test_param>("test_param")
.def_readwrite("obj", &test_param::obj)
.def(const_self == const_self)
];
Run Code Online (Sandbox Code Playgroud)
不会改变结果.
我也尝试从[]运算符切换到settable()和gettable().结果是一样的.我可以看到调试器调用了键的默认转换,所以我猜错误来自其中的某个地方,但我不知道究竟是什么问题.
如下面的简单测试用例所示,Luabind对复杂类型的转换肯定存在错误:
struct test_param : wrap_base
{
int obj;
bool operator==(test_param const& rhs) const
{ return obj == rhs.obj ; }
};
void test_main(lua_State* L)
{
using namespace luabind;
module(L)
[
class_<test_param>("test_param")
.def(constructor<>())
.def_readwrite("obj", &test_param::obj)
.def(const_self == const_self)
];
object tabc, zzk, zzv;
test_param tp, tp1;
tp.obj = 123456;
// create new table
tabc = newtable(L);
// set tabc[tp] = 5;
// o k v
settable( tabc, tp, 5);
// get access to entry through iterator() API
iterator zzi(tabc);
// get the key object
zzk = zzi.key();
// read back the value through gettable() API
// o k
zzv = gettable(tabc, zzk);
// check the entry has the same value
// irrespective of access method
TEST_CHECK ( *zzi == 5 &&
object_cast<int>(zzv) == 5 );
// convert key to its REAL type (test_param)
tp1 = object_cast<test_param>(zzk);
// check two keys are the same
TEST_CHECK( tp == tp1 );
// read the value back from table using REAL key type
zzv = gettable(tabc, tp1);
// check the value
TEST_CHECK( object_cast<int>(zzv) == 5 );
// the previous call FAILS with
// Terminated with exception: "unable to make cast"
// this is because gettable() doesn't return
// a TRUE value, but nil instead
}
Run Code Online (Sandbox Code Playgroud)
希望比我聪明的人可以解决这个问题,谢谢
我已经将问题追溯到这样一个事实,即每当你使用复数值作为键时,Luabind就会创建一个新的DISTINCT对象(但如果使用原始值或对象则不会).
这是一个小的测试用例,用于演示:
struct test_param : wrap_base
{
int obj;
bool operator==(test_param const& rhs) const
{ return obj == rhs.obj ; }
};
void test_main(lua_State* L)
{
using namespace luabind;
module(L)
[
class_<test_param>("test_param")
.def(constructor<>())
.def_readwrite("obj", &test_param::obj)
.def(const_self == const_self)
];
object tabc, zzk, zzv;
test_param tp;
tp.obj = 123456;
tabc = newtable(L);
// o k v
settable( tabc, tp, 5);
iterator zzi(tabc), end;
std::cerr << "value = " << *zzi << "\n";
zzk = zzi.key();
// o k v
settable( tabc, tp, 6);
settable( tabc, zzk, 7);
for (zzi = iterator(tabc); zzi != end; ++zzi)
{
std::cerr << "value = " << *zzi << "\n";
}
}
Run Code Online (Sandbox Code Playgroud)
注意tabc [tp]如何首先具有值5,然后在通过密钥对象访问时被7覆盖.但是,当通过tp访问AGAIN时,会创建一个新条目.这就是gettable()随后失败的原因.
大卫,大卫
免责声明:我不是 luabind 方面的专家。我完全有可能错过了有关 luabind 功能的某些内容。
首先,luabind 在将 test_param 转换为 Lua key 时做了什么?默认策略是复制。引用 luabind 文档:
这将创建参数的副本。这是按值传递参数时的默认行为。请注意,这只能在从 C++ 传递到 Lua 时使用。此策略要求参数类型具有可访问的复制构造函数。
实际上,这意味着 luabind 将创建一个由 Lua 垃圾收集器拥有的新对象(称为“完整用户数据”),并将您的结构复制到其中。这是一件非常安全的事情,因为你对 C++ 对象做什么不再重要;Lua 对象会一直存在,而不会产生任何开销。这是对按值排序的对象进行绑定的好方法。
为什么每次将 luabind 传递给 Lua 时都会创建一个新对象?嗯,它还能做什么呢?传递的对象的地址是否相同并不重要,因为原始的 C++ 对象自从第一次传递给 Lua 以来可能已经更改或被销毁。(记住,它是按值复制到 Lua 的,而不是按引用复制的。)因此,仅使用 ==,luabind 就必须维护曾经传递给 Lua 的该类型的每个对象的列表(可能是弱的),并比较您的值。对照每一个来看看它是否匹配。luabind 不会这样做(我也不认为应该这样做)。
现在,让我们看看 Lua 方面。即使 luabind 创建了两个不同的对象,它们仍然是相等的,对吧?嗯,第一个问题是,除了某些内置类型之外,Lua 只能通过引用来保存对象。我之前提到的每一个“完整用户数据”实际上都是一个指针。这意味着它们并不相同。
但如果我们定义 __eq 元操作,它们是相等的。不幸的是,Lua 本身根本不支持这种情况。无论如何,用作表键的用户数据总是按身份进行比较。这实际上对于用户数据来说并不特殊;对于表格也是如此。(请注意,为了正确支持这种情况,除了 __eq 之外,Lua 还需要重写对象上的 hashcode 操作。Lua 也不支持重写 hashcode 操作。)我不能代表 Lua 的作者说为什么他们不支持允许这样做(之前已经建议过),但事实就是如此。
那么,有哪些选择呢?
当使用包装器将注册类的指针或引用传递给 Lua 时,luabind 将查询它的动态类型。如果动态类型继承自wrap_base,则保留对象标识。