在将 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 中将函数参数和返回值作为模板参数传递。