1

我遇到了 Luabind 的问题,如果没有一些过于简化的解决方案,我不确定如何解决。

Luabind 似乎只允许使用__cdecl调用约定绑定到函数。在我当前的项目中,所有暴露给扩展/插件的功能都是使用__stdcall. 这使我无法直接绑定暴露的对象,而是必须为暴露的对象制作包装器。这很好,但有很多对象需要包装。

例如,一个对象可能如下所示:

struct IObject
{
    void __stdcall SomeFunc1( void );
    void __stdcall SomeFunc2( const char* );
};

struct IObjectContainer
{
    IObject* __stdcall GetObject( int );
    IObject* __stdcall GetObject( const char* );
};

struct IObjectCore
{
    IObjectContainer* __stdcall GetObjectContainer();
};

我目前没有更改整个项目调用约定的选项,因此我正在查看是否有人有解决方案来修补 Luabind 以使用__stdcall函数。我在模板和增强功能方面不是最好的,所以我个人不确定从哪里开始尝试添加使用__stdcall功能的能力。

作为参考,我正在使用:

  • 路亚 5.1.4
  • Luabind 0.9.1
  • VS2010

Lua 和 Luabind 都是其版本的最新版本。(出于项目限制的原因,不使用 Lua 5.2,但如果__stdcall5.2/Luabind 有修复,我也很乐意接受。)

我只能找到一个非常旧版本的 Luabind 的修复程序来执行此操作,但网上浮动的补丁仍然与当前的 Luabind 代码完全不符。

如果需要任何其他信息,请随时询问。

4

2 回答 2

2

可悲的是,由于不活动并且没有更多的搜索得到进一步的答案,我与项目开发人员进行了交谈,并且整个项目都被剥夺了 __stdcall。因此,现在通过 __cdecl 绑定都可以正常工作。不是我想走的路线,但现在一切都在按计划进行。

于 2012-11-22T18:39:50.237 回答
1

在将 OpenGL(使用 GLEW 函数)绑定到 Lua 时,我遇到了完全相同的问题,并使用可变参数模板解决了这个问题。

现在,如果该函数是全局的,并且您在编译时知道它的地址,那么您可以使用以下方法:

template<typename Signature>
struct wrap_known;

template<typename Ret, typename... Args>
struct wrap_known<Ret __stdcall (Args...)> {
    template <Ret __stdcall functor(Args...)>
    static Ret invoke(Args... arguments) {
        return functor(arguments...);
    }
};

// I know using macro is generally a bad idea but it's just shorter
#define wrap(f) wrap_known<decltype(f)>::invoke<f>

然后,在绑定时,使用这样的宏:

luabind::def("Clear", wrap(glClear)),
luabind::def("Vertex4f", wrap(glVertex4f))

但是,在您的情况下,我们有一堆成员函数,而不是像上面那样的全局函数。 以下是使用 __stdcall 调用约定包装成员函数的代码:

template<typename Signature>
struct wrap_mem;

template<typename Sub, typename Ret, typename... Args>
struct wrap_mem<Ret(__stdcall Sub::*) (Args...)> {

    template <Ret(__stdcall Sub::*functor) (Args...)>
    static Ret invoke(Sub* subject, Args... arguments) {
        return (subject->*functor)(arguments...);
    }
};

#define wrap_member(f) wrap_mem<decltype(f)>::invoke<f>

像这样使用它:

struct A {
    int __stdcall my_method(double b) {
        return 2;
    }
};

// ...
luabind::class_<A>("A")
.def("my_method", wrap_member(&A::my_method))

然而,有时,在编译时知道函数的地址并不那么幸运,例如 GLEW 就会发生这种情况。对于 glUniform*f、glGetUniformLocation 等函数,“wrap”宏将不起作用,因此我制作了另一个版本,用于在运行时包装函数:

template<typename Signature>
struct wrap_unknown;

template<typename Ret, typename... Args>
struct wrap_unknown<Ret (__stdcall*) (Args...)> {
    template <Ret (__stdcall** functor)(Args...)>
    static Ret invoke(Args... arguments) {
        return (**functor)(arguments...);
    }
};

#define wrap_ptr(f) wrap_unknown<decltype(f)>::invoke<&f>

(如果上面的代码吓到你了,这实际上是一个好兆头)

现在您可以像这样绑定 GLEW 函数:

luabind::def("Uniform4f", wrap_ptr(glUniform4f)),
luabind::def("GetUniformLocation", wrap_ptr(glGetUniformLocation))

只是不要让我编写另一个版本来将指针绑定到运行时已知的成员:)

如果您出于某种原因不想使用 C++11,您可以在此处了解如何在 C++03 中将函数参数和返回值作为模板参数传递

于 2014-01-16T02:15:38.973 回答