Thread overview
pointer to member function
Sep 05, 2005
Pinzo
Sep 05, 2005
Stewart Gordon
Sep 07, 2005
pinzo
Sep 08, 2005
Stewart Gordon
Sep 08, 2005
pinzo
September 05, 2005
Hello.
I'm translating some C++ code to D, and I have found a problem with a
pointer-to-member-function variable.

In C++ I have the following:
class Foo
{
void fun() {}
};

{
void (Foo::*pm)(); //Declare pm as pointer to member function
pm = &Foo::fun;    // assign
..
Foo o;             //Get an object
(o.*pm)();         //And call the pm into it!
}

Now, in D, I cannot get it work:

class Foo
{
void fun() {}
}

{
void function() pm;
pm = &Foo.fun;  // Get a completely useless pointer to function
..
Foo o;
//What do I do with o/pm
pm(); //  Crashes!!!
}

Delegates doesn't work either, because when I get the pointer to member, I don't have the reference to de object yet.

Am I losing something? Or would I have to resort to low-level tricks to workaround?

--
Pinzo
September 05, 2005
Pinzo wrote:
> Hello.
> I'm translating some C++ code to D, and I have found a problem with a
> pointer-to-member-function variable.

That's because D doesn't have pointers to members as such.  It has delegates instead.

<snip>
> class Foo
> {
> void fun() {}
> }
> 
> {

Huh?  What's this the body of?

> void function() pm;
> pm = &Foo.fun;  // Get a completely useless pointer to function
> ..
> Foo o;
> //What do I do with o/pm
> pm(); //  Crashes!!!
> }
> 
> Delegates doesn't work either, because when I get the pointer to member, I don't
> have the reference to de object yet.
> 
> Am I losing something? Or would I have to resort to low-level tricks to
> workaround?

You could define a static wrapper.  Only you'd need to wrap each function you're going to point it to.

----------
class Foo
{
    void fun() {}
    static void fun(Foo f) { f.fun(); }
}

void functionWithNoName() {
    void function(Foo) pm;
    pm = &Foo.fun;
    ..
    Foo o = new Foo;
    pm(o);
}
----------

Stewart.

-- 
-----BEGIN GEEK CODE BLOCK-----
Version: 3.1
GCS/M d- s:- C++@ a->--- UB@ P+ L E@ W++@ N+++ o K-@ w++@ O? M V? PS- PE- Y? PGP- t- 5? X? R b DI? D G e++>++++ h-- r-- !y
------END GEEK CODE BLOCK------

My e-mail is valid but not my primary mailbox.  Please keep replies on the 'group where everyone may benefit.
September 07, 2005
On Mon, 05 Sep 2005 15:01:27 +0200, Stewart Gordon <smjg_1998@yahoo.com> wrote:

>>  {
>
> Huh?  What's this the body of?
Eh? Doesn't care, just some generic code...

>
> You could define a static wrapper.  Only you'd need to wrap each function you're going to point it to.
>
> ----------
> class Foo
> {
>      void fun() {}
>      static void fun(Foo f) { f.fun(); }
> }

8-| I'm using this to handle windows messages, I just can't have ALL functions wrapped!!!

I have been reading the ABI and got the following quite-not-portable code:

union Delegate_Function
{
    void delegate() d;
    struct
    {
        Object o;
        void function() f;
    }
}
void callDF(Object o, void function() f)
{
    Delegate_Function df;
    df.o = o;
    df.f = f;
    df.d();
}

(Hey, it works!)

It would be nice to have portable versions for this and similar code into the standard library...

---
Pinzo
September 08, 2005
> <pinzo@correo.nu> wrote in message news:op.swq9bevjfo3y47@pinzopc2...
> On Mon, 05 Sep 2005 15:01:27 +0200, Stewart Gordon <smjg_1998@yahoo.com>
> wrote:
> 8-| I'm using this to handle windows messages, I just can't have ALL
> functions wrapped!!!

DFL, a Windows forms library for D that emulates .NET forms, uses delegates for wrapping all the controls' event handlers.  It has a pretty ingenious method, too.  The base class Control implements a wndProc method that will do something for each message.  Besides handling the message, it also calls the Control's corresponding on__ function; i.e. for WM_PAINT, it calls onPaint().  onPaint() then call's the Control's paint "event handler." EventHandler is actually a template which defines opCall().  EventHandler keeps a list of delegates which will be called when the message is sent to the control.  You can add to this list with ~=.  So it goes something like this:

class MyForm : Form    // class Form is part of DFL
{
    private void onButton1Click(Object sender, EventArgs ea)
    {
        // do something here
    }

    private Button mButton1;

    this()
    {
        mButton1 = new Button;
        mButton1.parent = this;
        mButton1.click ~= &onButton1Click;
    }
}

So whenever mButton1 is clicked, the delegate will be run.  Notice that the delegate isn't a member function of the Button class; it doesn't even have to be.


September 08, 2005
pinzo@correo.nu wrote:
<snip>
>> class Foo
>> {
>>      void fun() {}
>>      static void fun(Foo f) { f.fun(); }
>> }
> 
> 8-| I'm using this to handle windows messages, I just can't have ALL functions wrapped!!!

Then don't wrap ALL functions.  Wrap only the ones you're going to use as window procedures or whatever.

> I have been reading the ABI and got the following quite-not-portable code:
> 
> union Delegate_Function
> {
>     void delegate() d;
>     struct
>     {
>         Object o;
>         void function() f;
>     }
> }
> void callDF(Object o, void function() f)
> {
>     Delegate_Function df;
>     df.o = o;
>     df.f = f;
>     df.d();
> }
> 
> (Hey, it works!)
<snip>

What do you mean by "works" exactly?  How about sharing an example of code that calls this code?

Stewart.

-- 
-----BEGIN GEEK CODE BLOCK-----
Version: 3.1
GCS/M d- s:- C++@ a->--- UB@ P+ L E@ W++@ N+++ o K-@ w++@ O? M V? PS- PE- Y? PGP- t- 5? X? R b DI? D G e++>++++ h-- r-- !y
------END GEEK CODE BLOCK------

My e-mail is valid but not my primary mailbox.  Please keep replies on the 'group where everyone may benefit.
September 08, 2005
On Thu, 08 Sep 2005 11:01:59 +0200, Stewart Gordon <smjg_1998@yahoo.com> wrote:

>>  8-| I'm using this to handle windows messages, I just can't have ALL functions wrapped!!!
>
> Then don't wrap ALL functions.  Wrap only the ones you're going to use as window procedures or whatever.

The point here is that this code is a generic library, and I don't want to force
the clients to wrap the functions before they can use them.

> What do you mean by "works" exactly?  How about sharing an example of code that calls this code?

Works: behaves as intended.

I'll try to explain my code structure (simplified) and post a little extract of it.
The library has a class 'Wnd' that receives and handles window messages (WMs)
through the 'onMsg' virtual member function.

class Wnd
{
   ...
    bool onMsg(Msg *msg)
    {
         defWindowProc(msg);
         return false; //means 'default processed'
    }
}

Then, the clients can create subclass of 'Wnd' (e.g.: SubWnd) and say that this subclass wants
to handle certain WMs. For this, in C++ I had a collection of macros (ugh!) but in D I've created
a nice mixin (I like mixins, but I really like when I can use them!).
This mixin adds to the subclass a static associative array that maps WMs to function pointers.

template DECLARE_WND_MESSAGES()
{
protected:
    alias void function(Msg*) msgFun_t;
    static void WND_MESSAGE(UINT msg, msgFun_t msgFun)
    {
        assert(!(msg in s_msgMap));
        s_msgMap[msg] = msgFun;
    }
    bool onMsg(Msg *msg)
    {
        msgFun_t *msgFun = msg.uMsg in s_msgMap;
        if (msgFun)
        {
            Delegate_Function!(Msg*).call(this, *msgFun, msg); // **** HERE is the hack!
            return true;
        }
        return super.onMsg(msg);
    }
private:
    static msgFun_t[UINT] s_msgMap;
}

Then in the definition of the subclass, I associate the WM to the function in the
static constructor.

class WndFoo : public Wnd
{
    mixin DECLARE_WND_MESSAGES;

    static this()
    {
        WND_MESSAGE(WM_CREATE,  &onCreate);
    }

    void onCreate(Msg *msg)
    {
        ....
    }
}

Now, as Jarret suggested in this thread, I could have an array of delegates instead of
an array of functions. But then, I would have to make this array non-static, and the
initialization would be in the non-static constructor also.
IMHO, the flexibility you gain being able to handle a WM with a member function of another
class doesn't worth the additional cost of having the message map duplicated into each
of the window objects. And this flexibility isn't really so useful as it could seem,
because (IMHO again) it breaks encapsulation.

So, if I want a static WM map per subclass, I'll need pointers to member functions :-(

I have also put the Delegate_Function hack into a template so I can use it with
functions with different parameters.

I hope my intentions are clearer now. If you have any suggestions to improve this, they'll
be welcome.

--
Pinzo