2

我正在使用 Luabind 将 C++ API 绑定到 Lua。我有一些对象不能直接创建,而是必须在另一个线程上创建。我目前正在通过定义一个名为“静态”的成员来处理这个问题,该成员create在创建对象之前会产生:

luabind::class_<Foo>("Foo")
  .scope
  [
    luabind::def("create", &someCreateMethod, luabind::yield)
  ]

这可行,但缺点是使客户端 API 复杂化。对于这些类,您不能正常创建它们(例如local f = Foo()),而是需要创建它们local f = Foo.create()

是否可以定义一个实际上不调用 C++ 构造函数的 Luabind 构造函数,而是另一个返回构造对象的函数(同时可以产生)?我已经尝试为__initand定义绑定__call(后者在 a 下scope,以在类上定义它,而不是它的实例),但是这两种方法都没有成功。

4

2 回答 2

1

Luabind 中的构造函数必须是实际的 C++ 类构造函数。所以你只需要处理轻微的 API 怪异。

如果您感兴趣的只是能够Foo用作构造函数方法,那么您可以这样做。将您的 C++ 类注册FooFooLuaLua。然后,将 this 注册someCreateMethod为 的成员FooLua,而不是作为一个名为 的 Lua 自由函数Foo。因此,就用户而言,Foo是 Lua 类的构造函数Foo

现在,这将抑制您提供Foo其他静态属性(如成员等)的能力。但是你可以通过使用一些直接的 Lua API 编码来实现。您可以创建一个空表Foo并为其创建一个元表,用于转发__index__newindex调用FooLua. 同样,您可以覆盖此元表__call以将构造转发到Foo.create.

于 2011-11-13T23:57:44.907 回答
0

虽然 luabind 没有提供一种直接的方式来定义自定义构造函数,但实际上它可以通过一些 hack 来实现:

template<typename T,auto TCnstrct,typename ...TArgs>
static void custom_constructor(luabind::argument const &self_, TArgs... args)
{
    using holder_type = luabind::detail::value_holder<T>;
    luabind::detail::object_rep* self = luabind::touserdata<luabind::detail::object_rep>(self_);

    void* storage = self->allocate(sizeof(holder_type));
    self->set_instance(new (storage) holder_type(nullptr,TCnstrct(std::forward<TArgs>(args)...)));
}

template<typename T,auto TCnstrct,typename ...TArgs>
    static void define_custom_constructor(lua_State *l)
{
    auto *registry = luabind::detail::class_registry::get_registry(l);
    auto *crep = registry->find_class(typeid(T));
    assert(crep);
    auto fn = luabind::make_function(l,&custom_constructor<T,TCnstrct,TArgs...>);
    crep->get_table(l);
    auto o = luabind::object{luabind::from_stack(l,-1)};
    luabind::detail::add_overload(o,"__init",fn);
    lua_pop(l,1);
}

这将允许您在类定义之后使用任何自由函数作为构造函数:

static void define_vector_class(lua_State *l)
{
    auto modMath = luabind::module_(l,"math");
    struct Vector
    {
        Vector()=default;
        float x,y,z;
    };
    auto defVec = luabind::class_<Vector>("Vector");
    modMath[defVec];

    // Define custom constructor taking three float arguments
    define_custom_constructor<Vector,[](float x,float y,float z) -> Vector {
        Vector v;
        v.x = x;
        v.y = y;
        v.z = z;
        return v;
    },float,float,float>(l); // Constructor parameter types have to be specified in template parameter list as well
}

使用 luabind 的 deboostified 版本 ( https://github.com/decimad/luabind-deboostified ) 进行了测试,但它也应该适用于常规版本。

于 2021-08-28T15:58:17.727 回答