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

我目前正在使用GCC 4.4,我在void *和成员函数指针之间转换时遇到了麻烦。我正在尝试编写一个易于使用的库,将C ++对象绑定到Lua解释器,例如:

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

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

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)是无效的转换。有什么想法可以解决这个问题吗?

原文链接 https://stackoverflow.com/questions/1307278

点赞
stackoverflow用户29057
stackoverflow用户29057

不能将指向成员的指针转换为 void *,也不能转换为其他“常规”指针类型。指向成员的指针不像常规指针一样是地址。你最有可能需要做的是将成员函数包装在一个常规函数中。C++ FAQ Lite 对此进行了详细的解释。主要问题是实现指向成员指针所需的数据不仅仅是一个地址,并且实际上根据编译器的实现方式变化很大。

我假设你对用户数据 lua_touserdata 返回有控制权。它不能是一个指向成员的指针,因为没有合法的方法来取回这个信息。但你确实有其他选择:

  • 最简单的选择可能是将你的成员函数包装在一个自由函数中并返回它。该自由函数应将对象作为其第一个参数。请参阅下面的代码示例。
  • 使用类似于Boost.Bind's mem_fun 的技术返回一个函数对象,你可以适当地进行模板化。我认为这并不容易,但如果需要与函数返回关联的更多状态,则可以使用该方法。

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

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;
}
2009-08-20 16:30:43
stackoverflow用户153535
stackoverflow用户153535

由于将成员函数指针转换为 void* 的限制,您可以将函数指针包装在一个小的堆分配结构中,并将一个指向该结构的指针放入 Lua 用户数据中,以解决此问题:

template <typename T>
struct LuaUserData {
    typename void (T::*MemberProc)(int, int);

    explicit LuaUserData(MemberProc proc) :
        mProc(proc)
    { }

    MemberProc mProc;
};

LuaObject<Foo> lobj = registerObject(L, "foo", fooObject);
LuaUserData<Foo>* lobj_data = new LuaUserData<Foo>(&Foo::bar);

lobj.addField(L, "bar", lobj_data);

// ...

template <class T>
int call_int_function(lua_State *L)
{
    typedef LuaUserData<T>                       LuaUserDataType;
    typedef typename LuaUserDataType::MemberProc ProcType;

    // this next line is problematic
    LuaUserDataType* data =
        reinterpret_cast<LuaUserDataType*>(lua_touserdata(L, lua_upvalueindex(1)));
    T *obj = reinterpret_cast<T *>(lua_touserdata(L, 1));

    (obj->*(data.mMemberProc))(lua_tointeger(L, 2), lua_tointeger(L, 3));
    return 0;
}

我不熟悉 Lua,因此我可能会忽略上述示例中的某些内容。请记住,如果您选择这种方法,您将需要管理 LuaUserData 的分配。

2009-08-20 16:35:33
stackoverflow用户81145
stackoverflow用户81145

可以使用 union 将成员函数和属性指针进行转换:

// 帮助转换成员指针的 union
template<typename classT, typename memberT>
union u_ptm_cast {
    memberT classT::*pmember;
    void *pvoid;
};

要进行转换,将源值放入一个成员中,然后从另一个成员中取出目标值。

虽然这种方法很实用,但我不知道它是否在每种情况下都能正常工作。

2011-08-21 16:53:19
stackoverflow用户1250772
stackoverflow用户1250772

非静态 成员函数的地址不同,后者是一种具有复杂表示的成员指针类型,静态成员函数的地址通常只是一个可转换为 void* 的机器地址。

如果您需要将 C++ 的非静态成员函数绑定到基于 void* 的 C 或类 C 回调机制上,您可以尝试编写一个静态包装器。

该包装器可以将实例指针作为参数,并将控制权传递给非静态成员函数:

void myclass::static_fun(myclass *instance, int arge
{
   instance->nonstatic_fun(arg);
}

2016-01-06 05:09:23
stackoverflow用户3957710
stackoverflow用户3957710

下面是代码的中文翻译,且保留原本的 markdown 格式:

在这里,只需更改函数 void_cast 的参数以使其适应您的需求:

template<typename T, typename R>
void* void_cast(R(T::*f)())
{
    union
    {
        R(T::*pf)();
        void* p;
    };
    pf = f;
    return p;
}

使用示例:

auto pvoid = void_cast(&Foo::foo);
2016-05-28 18:57:16