在 void * 和指向成员函数的指针之间进行转换

2021-12-13 00:00:00 pointers lua c++ pointer-to-member

我目前正在使用 GCC 4.4,并且在 void* 和指向成员函数的指针之间进行转换时,我很头疼.我正在尝试编写一个易于使用的库,用于将 C++ 对象绑定到 Lua 解释器,如下所示:

I'm currently using GCC 4.4, and I'm having quite the headache casting between void* and a pointer to member function. I'm trying to write an easy-to-use library for binding C++ objects to a Lua interpreter, like so:

LuaObject<Foo> lobj = registerObject(L, "foo", fooObject);
lobj.addField(L, "bar", &Foo::bar);

我已经完成了大部分工作,除了以下函数(特定于某个函数签名,直到我有机会概括它):

I've got most of it done, except for the following function (which is specific to a certain function signature until I have a chance to generalize it):

template <class T>
int call_int_function(lua_State *L) 
{
    // this next line is problematic
    void (T::*method)(int, int) = reinterpret_cast<void (T::*)(int, int)>(lua_touserdata(L, lua_upvalueindex(1)));
    T *obj = reinterpret_cast<T *>(lua_touserdata(L, 1));

    (obj->*method)(lua_tointeger(L, 2), lua_tointeger(L, 3));
    return 0;
}

对于那些不熟悉 Lua 的人,lua_touserdata(L, lua_upvalueindex(1)) 获取与闭包关联的第一个值(在这种情况下,它是指向成员函数的指针)并返回它作为 void*.GCC 抱怨 void* -> void (T::*)(int, int) 是无效转换.关于如何解决这个问题的任何想法?

For those of you unfamiliar with Lua, lua_touserdata(L, lua_upvalueindex(1)) gets the first value associated with a closure (in this case, it's the pointer to member function) and returns it as a void*. GCC complains that void* -> void (T::*)(int, int) is an invalid cast. Any ideas on how to get around this?

推荐答案

你 不能将指向成员的指针转换为 void * 或任何其他常规"指针类型.指向成员的指针不是常规指针那样的地址.您最有可能需要做的是将您的成员函数包装在一个常规函数中.C++ FAQ Lite 详细解释了这一点.主要问题是实现成员指针所需的数据不仅仅是地址,实际上 根据编译器实现的不同而有很大差异.

You cannot cast a pointer-to-member to void * or to any other "regular" pointer type. Pointers-to-members are not addresses the way regular pointers are. What you most likely will need to do is wrap your member function in a regular function. The C++ FAQ Lite explains this in some detail. The main issue is that the data needed to implement a pointer-to-member is not just an address, and in fact varies tremendously based on the compiler implementation.

我认为您可以控制 lua_touserdata 返回的用户数据.它不能是指向成员的指针,因为没有合法的方法来获取此信息.但你还有其他一些选择:

I presume you have control over what the user data lua_touserdata is returning. It can't be a pointer-to-member since there isn't a legal way to get this information back out. But you do have some other choices:

  • 最简单的选择可能是将您的成员函数包装在一个自由函数中并返回它.该自由函数应将对象作为其第一个参数.请参阅下面的代码示例.

  • The simplest choice is probably to wrap your member function in a free function and return that. That free function should take the object as its first argument. See the code sample below.

使用类似于的技术Boost.Bind 的 mem_fun 返回一个函数对象,您可以适当地对其进行模板化.我不认为这更容易,但如果需要,它可以让您将更多状态与函数返回相关联.

Use a technique similar to that of Boost.Bind's mem_fun to return a function object, which you can template on appropriately. I don't see that this is easier, but it would let you associate the more state with the function return if you needed to.

这是使用第一种方式重写您的函数:

Here's a rewrite of your function using the first way:

template <class T>
int call_int_function(lua_State *L) 
{
    void (*method)(T*, int, int) = reinterpret_cast<void (*)(T*, int, int)>(lua_touserdata(L, lua_upvalueindex(1)));
    T *obj = reinterpret_cast<T *>(lua_touserdata(L, 1));

   method(obj, lua_tointeger(L, 2), lua_tointeger(L, 3));
   return 0;
}

相关文章