none
why casting member function pointer to void *& works? RRS feed

  • Question

  •  

    Hi forum,

    as stupid as this question may seem (and probably is), I can't really figure out the inner reason for the following:

     

    Code Block

    class A

    {

    public:

    void memfun (int par)

    {

    /*

    ... do whatever you want

    ...

    */

    }

    };

    void dosomething (void)

    {

    void *p1 = (void *)&A::memfun; //A) This fails

    void *p2 = (void *&)A::memfun; //B) This compiles

    void *p3 = (void *&)&A::memfun; //C) This fails

    }

     

     

     

    I'm using VisualStudio 2005 and for what I knew about pointers to member functions, you shouldn't be able to cast them to ordinary pointers.

    So I was happy with the behaviour of line A ( error C2440: 'type cast' : cannot convert from 'void (__thiscall A::* )(int)' to 'void *')

     

    But then I found in a code example something like line B, and now I'm getting crazy because I don't understand what/why does it make a difference to cast to (void *&) instead of (void *)? And then why it works only if I don't use the "address-of" operator (line C fails again with error C2102: '&' requires l-value)

     

    Is the VisualStudio 2005 doing something behind me? (g++ 4.0.1 doesn't accept even line B on Solaris, by the way).

     

    I've searched everywhere on the web, but didn't find anything specific to my question, so I'm asking here hoping someone will have some explanation...

     

    TIA,

    Andrea Bigagli

     

    Monday, January 14, 2008 3:54 PM

Answers

  • It's an awkward extension, that much is certain, and I have seen it in Microsoft libs such as Detours.

    What it'll actually do, however, is not grab a pointer to memfun, but rather the pointer stored at memfun's location. You're telling the compiler that A::memfun is a reference to a void pointer. This wil (for reasons I can only make out to be temporary reference implementation details) make the compiler treat A::memfun as a mix between a pointer-to-pointer and a regular pointer. Assigning it to something, such as your void pointer, will take an address of void* size from where A::memfun is stored -- because references to void pointers *behave* like void pointers. The storage, however, is similar to that of a double pointer.

    In other words, to get the address of the function itself, you'd have to modify your code to read "p2 = &(void*&)A::memfun".

    Why this was all allowed (intentionally or accidentally), I wouldn't know, but then again I never saw a problem with casting pointers to members into void pointers in the first place. Even without this cast enabled, you could easily grab the address through a construct such as

    union foo
    {
    void (*in)(int);
    void* out;
    };


    Monday, January 14, 2008 7:31 PM
    Moderator

All replies

  • Hello,


    I'm using VisualStudio 2005 and for what I knew about pointers to member functions, you shouldn't be able to cast them to ordinary pointers.

    Oh, but you can...
    Here's an article that covers all the aspects of this issue: Pointers To Members.

    Regards
    Monday, January 14, 2008 5:52 PM
  • It's an awkward extension, that much is certain, and I have seen it in Microsoft libs such as Detours.

    What it'll actually do, however, is not grab a pointer to memfun, but rather the pointer stored at memfun's location. You're telling the compiler that A::memfun is a reference to a void pointer. This wil (for reasons I can only make out to be temporary reference implementation details) make the compiler treat A::memfun as a mix between a pointer-to-pointer and a regular pointer. Assigning it to something, such as your void pointer, will take an address of void* size from where A::memfun is stored -- because references to void pointers *behave* like void pointers. The storage, however, is similar to that of a double pointer.

    In other words, to get the address of the function itself, you'd have to modify your code to read "p2 = &(void*&)A::memfun".

    Why this was all allowed (intentionally or accidentally), I wouldn't know, but then again I never saw a problem with casting pointers to members into void pointers in the first place. Even without this cast enabled, you could easily grab the address through a construct such as

    union foo
    {
    void (*in)(int);
    void* out;
    };


    Monday, January 14, 2008 7:31 PM
    Moderator
  • What it'll actually do, however, is not grab a pointer to memfun, but rather the pointer stored at memfun's location.

     

    That's true (and yes, it is an awkward extension, at best).  One must be very careful when calling the resulting function, however.  If the class (A in the example) uses multiple inheritance and/or virtual base classes then the value of the "this" pointer that needs to be passed to the function in some cases will be different from the value of an A* pointer.   When you call through a PMF, the compiler supplies an appropriate "this pointer adjustment" at the call site in the cases where it's needed.

     

    There are ways to correctly call the function that's referenced within a PMF, but suffice it to say that the best way is to simply use the PMF as it was intended and call through it using operator ->*.

    Monday, January 14, 2008 11:57 PM
    Moderator
  • Well, that quite makes a bit of sense, and I effectively found that piece of code in a Detours library sample, so you've definitively catched the point....

     

    Thanks,

    Andrea.

     

    Tuesday, January 15, 2008 9:34 AM