www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - pointer to member function

reply Pinzo <Pinzo_member pathlink.com> writes:
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
Sep 05 2005
parent reply Stewart Gordon <smjg_1998 yahoo.com> writes:
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.
Sep 05 2005
parent reply pinzo correo.nu writes:
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 cod= e: union Delegate_Function { void delegate() d; struct { Object o; void function() f; } } void callDF(Object o, void function() f) { Delegate_Function df; df.o =3D o; df.f =3D f; df.d(); } (Hey, it works!) It would be nice to have portable versions for this and similar code int= o = the standard library... --- Pinzo
Sep 07 2005
next sibling parent "Jarrett Billingsley" <kb3ctd2 yahoo.com> writes:
 <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.
Sep 07 2005
prev sibling parent reply Stewart Gordon <smjg_1998 yahoo.com> writes:
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.
Sep 08 2005
parent pinzo correo.nu writes:
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 th= at = 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] =3D msgFun; } bool onMsg(Msg *msg) { msgFun_t *msgFun =3D 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 functi= on = 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
Sep 08 2005