passing a pointer to member function problem

Discussion in 'C++' started by dice, Jul 18, 2006.

  1. dice

    dice Guest

    Hi,
    In order to use an external api call that requires a function pointer I
    am currently creating static wrappers to call my objects functions.
    I want to re-jig this so I only need 1 static wrapper function.
    I would prefer to be able to pass the member function as a void* to the
    static wrapper but I suspect this may not even be possible.
    Another solution would be option 2 below but I can't figure out the
    syntax to call obj->*pFn().

    Thanks in advance for any suggestions / observations.

    typedef void (*ExecFn)(void *);

    void external_api_fn(ExecFn fn,void* p)
    {
    fn(p);
    }

    class Doit
    {
    public:
    void fn1(void){printf("fn1\n");}
    void fn2(void){printf("fn2\n");}
    //current solution
    static void static_wrapper1(void *obj)
    {
    ((Doit*)obj)->fn1();
    }
    static void static_wrapper2(void *obj)
    {
    ((Doit*)obj)->fn2();
    }
    //option 1
    static void static_wrapper3(void *fn)
    {
    //fn();
    }
    //option 2
    void (Doit::*pFn)(void);
    static void static_wrapper4(void *obj)
    {
    //execute pFn - obj->*pFn - how to execute pFn for obj?
    }
    //--
    Doit()
    {
    //what Im doing
    external_api_fn(static_wrapper1,this);
    external_api_fn(static_wrapper2,this);
    //option 1 - cast fn1 to void?
    //external_api_fn(static_wrapper3,fn1);
    //external_api_fn(static_wrapper3,fn2);
    //option 2
    pFn = fn1;
    external_api_fn(static_wrapper4,this);
    pFn = fn2;
    external_api_fn(static_wrapper4,this);
    }
    };
     
    dice, Jul 18, 2006
    #1
    1. Advertising

  2. dice wrote:
    > Hi,
    > In order to use an external api call that requires a function pointer I
    > am currently creating static wrappers to call my objects functions.
    > I want to re-jig this so I only need 1 static wrapper function.


    The problem is that you need to pass the 'this' pointer to the function.

    > I would prefer to be able to pass the member function as a void* to the
    > static wrapper but I suspect this may not even be possible.


    As a matter of fact, taking the address of a method is possible, but
    wouldn't solve your problem, since you need to pass the 'this' pointer
    as well (so you actually have to pass _two_ parameters to the function).

    > Another solution would be option 2 below but I can't figure out the
    > syntax to call obj->*pFn().


    Of course. You don't have the 'this' pointer.

    > typedef void (*ExecFn)(void *);
    >
    > void external_api_fn(ExecFn fn,void* p)
    > {
    > fn(p);
    > }
    >
    > class Doit
    > {
    > public:
    > void fn1(void){printf("fn1\n");}
    > void fn2(void){printf("fn2\n");}
    > //current solution
    > static void static_wrapper1(void *obj)
    > {
    > ((Doit*)obj)->fn1();
    > }
    > static void static_wrapper2(void *obj)
    > {
    > ((Doit*)obj)->fn2();
    > }
    > //option 1
    > static void static_wrapper3(void *fn)
    > {
    > //fn();
    > }
    > //option 2
    > void (Doit::*pFn)(void);
    > static void static_wrapper4(void *obj)
    > {
    > //execute pFn - obj->*pFn - how to execute pFn for obj?
    > }
    > //--
    > Doit()
    > {
    > //what Im doing
    > external_api_fn(static_wrapper1,this);
    > external_api_fn(static_wrapper2,this);
    > //option 1 - cast fn1 to void?
    > //external_api_fn(static_wrapper3,fn1);
    > //external_api_fn(static_wrapper3,fn2);
    > //option 2
    > pFn = fn1;
    > external_api_fn(static_wrapper4,this);
    > pFn = fn2;
    > external_api_fn(static_wrapper4,this);
    > }
    > };
    >


    How about this:

    #include <stdio.h>

    typedef void (*ExecFn)(void);

    void external_api_fn (ExecFn fn)
    {
    fn ();
    }

    class Doit
    {
    typedef void (Doit::*PtrToMemberForWrapperType) (void);
    private:
    static Doit* ms_ThisForWrapper;
    static PtrToMemberForWrapperType ms_PtrMemberFuncForWrapper;

    static void static_wrapper ()
    {
    // Invoke the member function of the static object.
    (ms_ThisForWrapper->*ms_PtrMemberFuncForWrapper) ();
    }

    public:
    void fn1(void) {printf("fn1\n");}
    void fn2(void) {printf("fn2\n");}

    void call_external_api_fn (PtrToMemberForWrapperType pMemberFunc)
    {
    // Store away the this pointer.
    ms_ThisForWrapper = this;
    ms_PtrMemberFuncForWrapper = pMemberFunc;
    external_api_fn (&static_wrapper);
    }
    };

    Doit::ptrToMemberForWrapperType Doit::ms_PtrMemberFuncForWrapper = 0;
    Doit* Doit::ms_ThisForWrapper = 0;

    int main ()
    {
    Doit MyDoit;
    MyDoit.call_external_api_fn (Doit::fn1);

    return 0;
    }


    I took the liberty to change the definition of ExecFn to a function that
    takes no arguments, since your members fn1 and fn2 don't take arguments.
    The above solution is not intended for use in multi-threaded
    applications, since it uses static class members. If you want to use
    this in a multi-threaded app, you have to introduce a map that stores
    these pointers for each thread that uses the class.

    Regards,
    Stuart
     
    Stuart Redmann, Jul 18, 2006
    #2
    1. Advertising

  3. dice

    dice Guest

    Stuart Redmann wrote:
    > dice wrote:
    > > Hi,
    > > In order to use an external api call that requires a function pointer I
    > > am currently creating static wrappers to call my objects functions.
    > > I want to re-jig this so I only need 1 static wrapper function.

    >
    > The problem is that you need to pass the 'this' pointer to the function.
    >
    > > I would prefer to be able to pass the member function as a void* to the
    > > static wrapper but I suspect this may not even be possible.

    >
    > As a matter of fact, taking the address of a method is possible, but
    > wouldn't solve your problem, since you need to pass the 'this' pointer
    > as well (so you actually have to pass _two_ parameters to the function).


    yes - i wasn't quite thinking straight there, but see option 2 - this
    is essentially the same thing, pass the 'this' pointer after setting a
    function pointer in the object.

    >
    > > Another solution would be option 2 below but I can't figure out the
    > > syntax to call obj->*pFn().

    >
    > Of course. You don't have the 'this' pointer.


    'this' is passed as the second arg as per:
    external_api_fn(static_wrapper4,this);

    I thought that since the following is possible by passing 'this' as
    void* obj:
    ((Doit*)obj)->fn1();
    then static_wrapper4 could use something like the following:
    (((Doit*)obj)->*pFn)();

    >
    > > typedef void (*ExecFn)(void *);
    > >
    > > void external_api_fn(ExecFn fn,void* p)
    > > {
    > > fn(p);
    > > }
    > >
    > > class Doit
    > > {
    > > public:
    > > void fn1(void){printf("fn1\n");}
    > > void fn2(void){printf("fn2\n");}
    > > //current solution
    > > static void static_wrapper1(void *obj)
    > > {
    > > ((Doit*)obj)->fn1();
    > > }
    > > static void static_wrapper2(void *obj)
    > > {
    > > ((Doit*)obj)->fn2();
    > > }
    > > //option 1
    > > static void static_wrapper3(void *fn)
    > > {
    > > //fn();
    > > }
    > > //option 2
    > > void (Doit::*pFn)(void);
    > > static void static_wrapper4(void *obj)
    > > {
    > > //execute pFn - obj->*pFn - how to execute pFn for obj?
    > > }
    > > //--
    > > Doit()
    > > {
    > > //what Im doing
    > > external_api_fn(static_wrapper1,this);
    > > external_api_fn(static_wrapper2,this);
    > > //option 1 - cast fn1 to void?
    > > //external_api_fn(static_wrapper3,fn1);
    > > //external_api_fn(static_wrapper3,fn2);
    > > //option 2
    > > pFn = fn1;
    > > external_api_fn(static_wrapper4,this);
    > > pFn = fn2;
    > > external_api_fn(static_wrapper4,this);
    > > }
    > > };
    > >

    >
    > How about this:
    >
    > #include <stdio.h>
    >
    > typedef void (*ExecFn)(void);
    >
    > void external_api_fn (ExecFn fn)
    > {
    > fn ();
    > }
    >
    > class Doit
    > {
    > typedef void (Doit::*PtrToMemberForWrapperType) (void);
    > private:
    > static Doit* ms_ThisForWrapper;
    > static PtrToMemberForWrapperType ms_PtrMemberFuncForWrapper;
    >
    > static void static_wrapper ()
    > {
    > // Invoke the member function of the static object.
    > (ms_ThisForWrapper->*ms_PtrMemberFuncForWrapper) ();
    > }
    >
    > public:
    > void fn1(void) {printf("fn1\n");}
    > void fn2(void) {printf("fn2\n");}
    >
    > void call_external_api_fn (PtrToMemberForWrapperType pMemberFunc)
    > {
    > // Store away the this pointer.
    > ms_ThisForWrapper = this;
    > ms_PtrMemberFuncForWrapper = pMemberFunc;
    > external_api_fn (&static_wrapper);
    > }
    > };
    >
    > Doit::ptrToMemberForWrapperType Doit::ms_PtrMemberFuncForWrapper = 0;
    > Doit* Doit::ms_ThisForWrapper = 0;
    >
    > int main ()
    > {
    > Doit MyDoit;
    > MyDoit.call_external_api_fn (Doit::fn1);


    this builds and works on my evC++ compiler, but not with mingw32-g++

    >
    > return 0;
    > }
    >
    >
    > I took the liberty to change the definition of ExecFn to a function that
    > takes no arguments, since your members fn1 and fn2 don't take arguments.
    > The above solution is not intended for use in multi-threaded
    > applications, since it uses static class members. If you want to use


    Multi threading is not a problem in this particular instance, but I was
    trying to avoid static members for just this reason.

    > this in a multi-threaded app, you have to introduce a map that stores
    > these pointers for each thread that uses the class.
    >
    > Regards,
    > Stuart
     
    dice, Jul 18, 2006
    #3
  4. dice wrote:

    > Stuart Redmann wrote:
    >
    >>dice wrote:
    >>
    >>>Hi,
    >>>In order to use an external api call that requires a function pointer I
    >>>am currently creating static wrappers to call my objects functions.
    >>>I want to re-jig this so I only need 1 static wrapper function.
    >>>I would prefer to be able to pass the member function as a void* to the
    >>>static wrapper but I suspect this may not even be possible.
    >>>Another solution would be option 2 below but I can't figure out the
    >>>syntax to call obj->*pFn().


    I think I misunderstood you here. Invokation of member functions is
    quite ugly (I had to look it up myself). If you have the object and the
    pointer to the member function at hand, you can invoke it with the above
    syntax, e.g. obj->*pFn (), but you have to enclose this in parentheses:
    (obj->*pFn) ()

    >>>typedef void (*ExecFn)(void *);
    >>>
    >>>void external_api_fn(ExecFn fn,void* p)
    >>>{
    >>> fn(p);
    >>>}


    A even much simpler solution comes into my mind: Since your API function
    can be passed _any_ pointer, why don't we give it a pointer to a struct
    containing both the object pointer and the member function pointer?
    Something like this:

    #include <stdio.h>

    typedef void (*ExecFn)(void*);

    void external_api_fn (ExecFn fn, void* p)
    {
    fn (p);
    }

    class Doit
    {
    typedef void (Doit::*PtrToMemberForWrapperType) (void);
    struct SApiFunctionParameters
    {
    Doit* m_pThisPointer;
    PtrToMemberForWrapperType m_pMemberFunction;
    };

    private:
    static void static_wrapper (void* p_VoidPointer)
    {
    // Cast the passed pointer to a pointer to a parameter struct.
    SApiFunctionParameters* pParameters = (SApiFunctionParameters*)
    p_VoidPointer;

    // Invoke the passed member function for the passed 'this' pointer.
    (pParameters->m_pThisPointer->*pParameters->m_pMemberFunction) ();
    }

    public:
    void fn1(void) {printf("fn1\n");}
    void fn2(void) {printf("fn2\n");}

    void call_external_api_fn (PtrToMemberForWrapperType pMemberFunc)
    {
    // Store away the 'this' AND the member function pointer.
    SApiFunctionParameters ApiFunctionParameters;
    ApiFunctionParameters.m_pThisPointer = this;
    ApiFunctionParameters.m_pMemberFunction = pMemberFunc;
    external_api_fn (&static_wrapper, &ApiFunctionParameters);
    }
    };

    int main ()
    {
    Doit MyDoit;
    MyDoit.call_external_api_fn (Doit::fn1);

    return 0;
    }

    [snipped previous solution]
    >
    > this builds and works on my evC++ compiler, but not with mingw32-g++
    >


    (*blush*) I work with Visual C 6.0 (at least I have the courage to admit
    it). Sorry, I can't help you there.

    >
    > Multi threading is not a problem in this particular instance, but I was
    > trying to avoid static members for just this reason.
    >


    Luckily, multi-threading will be no problem when you use the struct version.

    Regards,
    Stuart
     
    Stuart Redmann, Jul 19, 2006
    #4
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.

Share This Page