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

发布于 2024-08-02 15:09:16 字数 919 浏览 6 评论 0原文

我目前正在使用 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) 是无效的强制转换。关于如何解决这个问题有什么想法吗?

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;
}

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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

胡大本事 2024-08-09 15:09:16

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

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

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

  • 使用类似于 Boost.Bind 的技术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;
}

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.

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.

  • 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;
}
浴红衣 2024-08-09 15:09:16

可以使用联合将指针转换为成员函数和属性:

// helper union to cast pointer to member
template<typename classT, typename memberT>
union u_ptm_cast {
    memberT classT::*pmember;
    void *pvoid;
};

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

虽然这种方法很实用,但我不知道它是否适用于所有情况。

It is possible to convert pointer to member functions and attributes using unions:

// helper union to cast pointer to member
template<typename classT, typename memberT>
union u_ptm_cast {
    memberT classT::*pmember;
    void *pvoid;
};

To convert, put the source value into one member, and pull the target value out of the other.

While this method is practical, I have no idea if it's going to work in every case.

不弃不离 2024-08-09 15:09:16

在这里,只需更改函数 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);

Here, just change the parameters of the function void_cast for it to fit your needs:

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

example use:

auto pvoid = void_cast(&Foo::foo);
寒冷纷飞旳雪 2024-08-09 15:09:16

作为一种解决方法,考虑到将成员函数指针转换为 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 的分配。

As a workaround given the restrictions of casting a pointer-to-member-function to void* you could wrap the function pointer in a small heap-allocated struct and put a pointer to that struct in your Lua user data:

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;
}

I'm not savvy with Lua so I have likely overlooked something in the above example. Keep in mind, too, if you go this route you'll have to manage the LuaUserData's allocation.

一花一树开 2024-08-09 15:09:16

非静态成员函数的地址(具有复杂表示的指向成员类型的指针)不同,静态成员函数的地址通常只是一个机器地址,与 void * 的转换兼容。

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

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

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

Unlike the address of a nonstatic member function, which is a pointer-to-member type with a complicated representation, the address of a static member function is usually a just a machine address, compatible with a conversion to void *.

If you need to bind a C++ non-static member function to a C or C-like callback mechanism based on void *, what you can try to do is write a static wrapper instead.

The wrapper can take a pointer to an instance as an argument, and pass control to the nonstatic member function:

void myclass::static_fun(myclass *instance, int arg)
{
   instance->nonstatic_fun(arg);
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文