Luabind调用约定问题

我正在使用 Luabind 时遇到问题,不确定如何解决,而不使用一些过于简单的解决方案。

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

例如,一个对象可以像这样:

结构IObject
{
   void__stdcall SomeFunc1(void);
   void__stdcall SomeFunc2(const char *);
};

结构IObjectContainer
{
   IObject *__ stdcall GetObject(int);
   IObject *__ stdcall GetObject(const char *);
};

结构IObjectCore
{
   IObjectContainer *__ stdcall GetObjectContainer();
};

目前,我无法更改整个项目的调用约定,因此我正在寻找解决方案,以修补Luabind与__stdcall函数一起使用的能力。我对模板和boost不是很熟悉,因此我个人不确定从哪里开始尝试添加使用__stdcall函数的能力。

参考资料:

  • Lua 5.1.4
  • Luabind 0.9.1
  • VS2010

Lua和Luabind都是最新版本的库。(由于项目限制原因,不使用Lua 5.2,但如果有针对5.2 / Luabind的__stdcall修复方法,我也很乐意采用。)

我只能找到一个非常古老的版本的Luabind的修复方法,但是在网上流传的补丁与当前Luabind代码完全不符。

如果还需要其他信息,请随时问。

点赞
用户1080150
用户1080150

非常遗憾,由于长时间没有活动并且搜索没有得到更多的答案,我与项目开发人员交谈,将整个项目取消了 __stdcall。因此,绑定现在都可以通过 __cdecl 正常工作。这不是我想要采取的方法,但现在计划中的事情都正常工作了。

2012-11-22 18:39:50
用户503776
用户503776

当将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...);
    }
};

// 我知道使用宏通常不是很好的主意,但是它只是更短
#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-16 02:15:38