Casting between void * and a pointer to member function

前端 未结 5 1805
故里飘歌
故里飘歌 2020-11-27 07:25

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 li

相关标签:
5条回答
  • 2020-11-27 08:05

    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.

    0 讨论(0)
  • 2020-11-27 08:07

    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);
    
    0 讨论(0)
  • 2020-11-27 08:12

    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);
    }
    
    0 讨论(0)
  • 2020-11-27 08:20

    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;
    }
    
    0 讨论(0)
  • 2020-11-27 08:24

    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.

    0 讨论(0)
提交回复
热议问题