Luabind 中的自定义构造函数

发布于 2024-12-15 21:45:01 字数 572 浏览 2 评论 0原文

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

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

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

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

I'm using Luabind to bind a C++ API to Lua. I have some objects that cannot be created directly, but rather must be created on another thread. I'm currently handling this by defining a "static" member called create that yields until the object is created:

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

This works, but has the disadvantage of complicating the client API. For these classes, you cannot create them normally (e.g. local f = Foo()), but instead need to do local f = Foo.create().

Is it possible to define a Luabind constructor that doesn't actually call the C++ constructor, but instead another function that returns the constructed object (and can yield in the meantime)? I've tried defining bindings for __init and __call (the latter under a scope, to define it on the class, not its instances), but I didn't have success with either approach.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

风追烟花雨 2024-12-22 21:45:01

Luabind 中的构造函数必须是实际的 C++ 类构造函数。所以你只需要处理 API 的一些奇怪问题。

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

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

Constructors in Luabind must be actual C++ class constructors. So you'll just have to deal with the slight API weirdness.

If all you're interested in is the ability to use Foo as a constructor method, then you can do this. Register your C++ class Foo as FooLua to Lua. Then, register this someCreateMethod, not as a member of FooLua, but as just a Lua free function called Foo. Thus, as far as the user is concerned, Foo is a constructor for the Lua class Foo.

Now, this will inhibit your ability to give Foo other static properties, like members and so forth. But you could accomplish that by using some direct Lua API coding. You can create an empty table Foo and create a metatable for it that forwards __index and __newindex calls to FooLua. Similarly, you can override this metatable's __call to forward the construction to Foo.create.

别理我 2024-12-22 21:45:01

虽然 luabind 没有提供定义自定义构造函数的直接方法,但实际上可以通过一些技巧实现:

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),但它也应该适用于常规版本。

While luabind doesn't provide a straight-forward way of defining custom constructors, it is in fact possible with a bit of a 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);
}

This will allow you to use any free function as a constructor after the class definition:

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
}

Tested with the deboostified version of luabind (https://github.com/decimad/luabind-deboostified), but it should work with the regular version as well.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文