www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - C++ Macro to D mixin template, delegates Please help

reply BLS <nanali nospam-wanadoo.fr> writes:
Please have a look on my translation.
Problems are
1) porting C++ macros
2) use of delegates within template mixins

/*  THE C++ Stuff , a fragment
class CMsg
{
public:

	virtual BOOL NewMsgProc(HWND hWnd, UINT uID, WPARAM wParam, LPARAM 
lParam,LRESULT lResult)
	{
		return FALSE;
	}
};


#define BEGIN_MSG_MAP() \
public: \
	virtual BOOL NewMsgProc(HWND hWnd, UINT uID, WPARAM wParam, LPARAM 
lParam,LRESULT& lResult) \
	{ \
		

#define ON_WM_CLOSE(vfunc)\
	if (uID == WM_CLOSE) \
	{ \
		lResult =vfunc(); \
		return lResult; \
	}

// and so on ............



class CWin : public CMsg
{

public:	

	virtual BOOL OnClose()
	{
		return TRUE;
	}


     BEGIN_MSG_MAP()
         ON_WM_CLOSE(OnClose)
         ON_WM_DESTROY(OnDestroy)
         ON_WM_NCDESTROY(OnNcDestroy)
     END_MSG_MAP_DEFAULT()
	

}

EOF C++ stuff */

THE D port
module dgt.win;

  // All Window's messages will be mapped in this function
class CMsg
{
public:

     bool NewMsgProc(HWND hWnd, UINT uID, WPARAM wParam, LPARAM 
lParam,LRESULT lResult)
     {
         return false;
     }

}

template ON_WM_CLOSE(D) (D delegate() dg)
{
     if (uID == WM_CLOSE)
     {
         lResult = dg();
         return lResult;
     }
}

template ON_MESSAGE_RANGE(M1, M2, D) (M1 MsgF, M2 MsgL, D delegate(...) dg )
{
     if(uID >= MsgF && uID <= MsgL)
      {
         lResult = dg(uID, wParam, lParam);
          return true;
      }
}



// Window
  class CWin : CMsg
{

public:	
     bool onClose()
     {
         return true;
     }

     override bool NewMsgProc(HWND hWnd, UINT uID, WPARAM wParam, LPARAM 
lParam, ref LRESULT lResult)
     {
         mixin ON_WM_CLOSE!(&CWin.OnClose);
     }
}

--------------------
Okay, I've ported it as good as I can... the available tutorials are not 
very helpfull in this case. So please help
Bjoern
Sep 20 2007
next sibling parent reply Regan Heath <regan netmail.co.nz> writes:
BLS wrote:
 template ON_WM_CLOSE(D) (D delegate() dg)
 {
     if (uID == WM_CLOSE)
     {
         lResult = dg();
         return lResult;
     }
 }

This seems to be mixing template syntax (using "template") with template function syntax (using "(D)(D delegate() dg)". I don't think you want a template function so, rather something like: template ON_WM_CLOSE(alias D) { if (uID == WM_CLOSE) { lResult = D(); return lResult; } } (see the duffs_device example here http://www.digitalmars.com/d/template-mixin.html) However this wont work because a template body can only contain 'declarations' which means; Declaration: typedef Decl alias Decl Decl Decl: StorageClasses Decl BasicType Declarators ; BasicType Declarator FunctionBody AutoDeclaration So, you can put typedefs, aliases, variables and functions in a template, but, what you can't do is put an "if" statement in there. So, templates and mixins in D just can't achieve the same effect as the C/C++ define macro can. The planned/propsed D macro feature however, that should do what you want I reckon. Regan
Sep 20 2007
parent reply BLS <nanali nospam-wanadoo.fr> writes:
Regan Heath schrieb:
 BLS wrote:
 template ON_WM_CLOSE(D) (D delegate() dg)
 {
     if (uID == WM_CLOSE)
     {
         lResult = dg();
         return lResult;
     }
 }

This seems to be mixing template syntax (using "template") with template function syntax (using "(D)(D delegate() dg)". I don't think you want a template function so, rather something like: template ON_WM_CLOSE(alias D) { if (uID == WM_CLOSE) { lResult = D(); return lResult; } } (see the duffs_device example here http://www.digitalmars.com/d/template-mixin.html) However this wont work because a template body can only contain 'declarations' which means; Declaration: typedef Decl alias Decl Decl Decl: StorageClasses Decl BasicType Declarators ; BasicType Declarator FunctionBody AutoDeclaration So, you can put typedefs, aliases, variables and functions in a template, but, what you can't do is put an "if" statement in there. So, templates and mixins in D just can't achieve the same effect as the C/C++ define macro can. The planned/propsed D macro feature however, that should do what you want I reckon. Regan

NOOOOOOOOOOoooooooo, Shi* ! So I guess template TFoo(D) { alias D delegate() dg } is also not allowed... Hell, there should be a way to translate such a simple C++ macro without without having so much trouble!!! I can not imagine that it is impossible. Probabely there exist a workaround. have to look at the Tango Signal/Slot implementation.. Imean they 've managed it. However, thanks Regan Bjoern
Sep 20 2007
parent reply Regan Heath <regan netmail.co.nz> writes:
BLS wrote:
 Regan Heath schrieb:
 BLS wrote:
 template ON_WM_CLOSE(D) (D delegate() dg)
 {
     if (uID == WM_CLOSE)
     {
         lResult = dg();
         return lResult;
     }
 }

This seems to be mixing template syntax (using "template") with template function syntax (using "(D)(D delegate() dg)". I don't think you want a template function so, rather something like: template ON_WM_CLOSE(alias D) { if (uID == WM_CLOSE) { lResult = D(); return lResult; } } (see the duffs_device example here http://www.digitalmars.com/d/template-mixin.html) However this wont work because a template body can only contain 'declarations' which means; Declaration: typedef Decl alias Decl Decl Decl: StorageClasses Decl BasicType Declarators ; BasicType Declarator FunctionBody AutoDeclaration So, you can put typedefs, aliases, variables and functions in a template, but, what you can't do is put an "if" statement in there. So, templates and mixins in D just can't achieve the same effect as the C/C++ define macro can. The planned/propsed D macro feature however, that should do what you want I reckon. Regan

NOOOOOOOOOOoooooooo, Shi* ! So I guess template TFoo(D) { alias D delegate() dg } is also not allowed...

This one is allowed, 'alias' is a declaration.
 Hell, there should be a way to translate such a simple C++ macro without 
 without having so much trouble!!!

The proposed macro feature should be able to do it.
 I can not imagine that it is impossible. Probabely there exist a
 workaround. have to look at the Tango Signal/Slot implementation.. Imean
 they 've managed it.

Good idea. I wonder how they're doing it. It's entirely possible that I'm getting something wrong here, I'm no template master. Regan
Sep 20 2007
parent reply BLS <nanali nospam-wanadoo.fr> writes:
Regan Heath schrieb:
 BLS wrote:
 Regan Heath schrieb:
 BLS wrote:
 template ON_WM_CLOSE(D) (D delegate() dg)
 {
     if (uID == WM_CLOSE)
     {
         lResult = dg();
         return lResult;
     }
 }

This seems to be mixing template syntax (using "template") with template function syntax (using "(D)(D delegate() dg)". I don't think you want a template function so, rather something like: template ON_WM_CLOSE(alias D) { if (uID == WM_CLOSE) { lResult = D(); return lResult; } } (see the duffs_device example here http://www.digitalmars.com/d/template-mixin.html) However this wont work because a template body can only contain 'declarations' which means; Declaration: typedef Decl alias Decl Decl Decl: StorageClasses Decl BasicType Declarators ; BasicType Declarator FunctionBody AutoDeclaration So, you can put typedefs, aliases, variables and functions in a template, but, what you can't do is put an "if" statement in there. So, templates and mixins in D just can't achieve the same effect as the C/C++ define macro can. The planned/propsed D macro feature however, that should do what you want I reckon. Regan

NOOOOOOOOOOoooooooo, Shi* ! So I guess template TFoo(D) { alias D delegate() dg } is also not allowed...

This one is allowed, 'alias' is a declaration.

template ON_WM_CLOSE(D) { alias D delegate() dg; if (uID == WM_CLOSE) { lResult = dg(); return lResult; } } // is legal ?
 Hell, there should be a way to translate such a simple C++ macro 
 without without having so much trouble!!!

The proposed macro feature should be able to do it.

ending story, and now I have to create a GUI for it...
 I can not imagine that it is impossible. Probabely there exist a
 workaround. have to look at the Tango Signal/Slot implementation.. Imean
 they 've managed it.

Good idea. I wonder how they're doing it. It's entirely possible that I'm getting something wrong here, I'm no template master. Regan

Well I think I'll ask the Tango folks whether (and how) I can use the Signal/Slot stuff INSTEAD. Bjoern
Sep 20 2007
parent Regan Heath <regan netmail.co.nz> writes:
BLS wrote:
 // Means
 template ON_WM_CLOSE(D)
 {
     alias D delegate() dg;
     if (uID == WM_CLOSE)
     {
         lResult = dg();
         return lResult;
     }
 }
 // is legal ?

Nope. Only the alias line is legal, the rest is illegal because "if" is not a "declaration", it is a "statement".
 Hell, there should be a way to translate such a simple C++ macro 
 without without having so much trouble!!!

The proposed macro feature should be able to do it.

ending story, and now I have to create a GUI for it...

I'm hoping it arrives faster than that, but I guess you can't really bank on it. Walters last foray into the forums was about 'const' so I expect he's working on that as a top priority, but I could be wrong.
 I can not imagine that it is impossible. Probabely there exist a
 workaround. have to look at the Tango Signal/Slot implementation.. Imean
 they 've managed it.

Good idea. I wonder how they're doing it. It's entirely possible that I'm getting something wrong here, I'm no template master. Regan

Well I think I'll ask the Tango folks whether (and how) I can use the Signal/Slot stuff INSTEAD.

I might have a peek in there myself, out of interest :) Regan
Sep 20 2007
prev sibling next sibling parent reply Henning Hasemann <hhasemann web.de> writes:
Does this help you?


import std.stdio;

template MessageMap(Mappings ...) {
  void newMsgProc(uint uID) {
     foreach(mapping; Mappings) {
       if(mapping.matches(uID))
         mapping.executeAction();
     }
  }
}

struct OnClose(alias fn) {
  alias fn executeAction;
  static bool matches(uint uid) { return uid == 5; }
}

struct OnRange(uint a, uint b, alias fn) {
  alias fn executeAction;
  static bool matches(uint uid) { return uid >= a && uid <= b; }
}


class Foo {
  void foo() {
    writefln("foo called");
  }
  void bar() {
    writefln("bar called");
  }

  mixin MessageMap!(
    OnClose!(foo),
    OnRange!(1, 3, bar)
  );

}

void main() {
  auto f = new Foo;
  f.newMsgProc(5);
  f.newMsgProc(2);
}

-- 
GPG Public Key:
http://keyserver.ganneff.de:11371/pks/lookup?op=get&search=0xDDD6D36D41911851
Fingerprint: 344F 4072 F038 BB9E B35D  E6AB DDD6 D36D 4191 1851
Sep 20 2007
parent reply Regan Heath <regan netmail.co.nz> writes:
Henning Hasemann wrote:
 
 Does this help you?
 
 
 import std.stdio;
 
 template MessageMap(Mappings ...) {
   void newMsgProc(uint uID) {
      foreach(mapping; Mappings) {
        if(mapping.matches(uID))
          mapping.executeAction();
      }
   }
 }
 
 struct OnClose(alias fn) {
   alias fn executeAction;
   static bool matches(uint uid) { return uid == 5; }
 }
 
 struct OnRange(uint a, uint b, alias fn) {
   alias fn executeAction;
   static bool matches(uint uid) { return uid >= a && uid <= b; }
 }
 
 
 class Foo {
   void foo() {
     writefln("foo called");
   }
   void bar() {
     writefln("bar called");
   }
 
   mixin MessageMap!(
     OnClose!(foo),
     OnRange!(1, 3, bar)
   );
 
 }
 
 void main() {
   auto f = new Foo;
   f.newMsgProc(5);
   f.newMsgProc(2);
 }
 

Genius! :) See BLS I told you someone else would come up with something. Sadly my mind doesn't operate in a very templatey fashion .. yet .. I need more practice. Regan
Sep 21 2007
next sibling parent BLS <nanali nospam-wanadoo.fr> writes:
Regan Heath schrieb:
 Henning Hasemann wrote:
 Does this help you?


 import std.stdio;

 template MessageMap(Mappings ...) {
   void newMsgProc(uint uID) {
      foreach(mapping; Mappings) {
        if(mapping.matches(uID))
          mapping.executeAction();
      }
   }
 }

 struct OnClose(alias fn) {
   alias fn executeAction;
   static bool matches(uint uid) { return uid == 5; }
 }

 struct OnRange(uint a, uint b, alias fn) {
   alias fn executeAction;
   static bool matches(uint uid) { return uid >= a && uid <= b; }
 }


 class Foo {
   void foo() {
     writefln("foo called");
   }
   void bar() {
     writefln("bar called");
   }

   mixin MessageMap!(
     OnClose!(foo),
     OnRange!(1, 3, bar)
   );

 }

 void main() {
   auto f = new Foo;
   f.newMsgProc(5);
   f.newMsgProc(2);
 }

Genius! :) See BLS I told you someone else would come up with something. Sadly my mind doesn't operate in a very templatey fashion .. yet .. I need more practice. Regan

I really hope that I can use mixins (NOT template mixins) let me show you : //A C++ fragment from the MSG_MAP macro #define ON_WM_CLOSE(vfunc)\ if (uID == WM_CLOSE) \ { \ lResult =vfunc(); \ return lResult; \ } // becomes in D template ON_WM_CLOSE(char[] vfunc) { const char[] ON_WM_CLOSE = "if (uID == WM_CLOSE) { lResult = " ~ vfunc ~ "; return lResult; }"; } //use case : mixin(ON_WM_CLOSE!("onClose()")) Let's have a look at : 1) The original C++ class class CWin : public CMsg { public: virtual BOOL OnClose() { return TRUE; } BEGIN_MSG_MAP() ON_WM_CLOSE(OnClose) END_MSG_MAP_DEFAULT() ] -------------------------------------------- which expands to class CWin : public CMsg { public: virtual BOOL OnClose() { return TRUE; } // BEGIN_MSG_MAP virtual BOOL NewMsgProc(HWND hWnd, UINT uID, WPARAM wParam, LPARAM lParam,LRESULT& lResult) { //ON_WM_CLOSE if (uID == WM_CLOSE) { lResult =onClose(); // CALL onClose !! AND SET lResult return lResult; } //END_MSG_MAP_DEFAULT() // whatever } 2) The D code class CWin : CMsg { public: bool onClose() { return true; } // C++ BEGIN_MSG_MAP() becomes override bool NewMsgProc(HWND hWnd, UINT uID, WPARAM wParam, LPARAM lParam, ref LRESULT lResult) { mixin(ON_WM_CLOSE!("onClose()")) //C++ ON_WM_CLOSE(OnClose) } } --------------------------------------------------------------------------- //Again the D ON_WM_CLOSE mixin template ON_WM_CLOSE(char[] vfunc) { const char[] ON_WM_CLOSE = "if (uID == WM_CLOSE) { lResult = " ~ vfunc ~ "; return lResult; }"; } Comments ? Is it legal to use mixins this way ? http://www.digitalmars.com/d/mixin.html It seems that C++ macros are just text substitutions. I was really confused about the "lResult = vFunc() stuff within the ON_WM_CLOSE #define. Dunno much about C++ but the more I learn the more I hate it. :-) Bjoern
Sep 21 2007
prev sibling parent reply Regan Heath <regan netmail.co.nz> writes:
BLS wrote:
 Regan Heath schrieb:
 Henning Hasemann wrote:


I don't understand. What doesn't the code Henning posted do, that you need it to do?? class Foo { void foo() { writefln("foo called"); } void bar() { writefln("bar called"); } mixin MessageMap!( OnClose!(foo), OnRange!(1, 3, bar) ); } expands to: class Foo { void foo() { writefln("foo called"); } void bar() { writefln("bar called"); } void newMsgProc(uint uID) { //expands just like "BEGIN_MSG_MAP" foreach(mapping; Mappings) { //loops 2x if(mapping.matches(uID)) //just like "if (uID == WM_CLOSE)" mapping.executeAction(); //just like "vfunc();" } } } Change MessageMap to expand to the function fignature you want, i.e. template MessageMap(Mappings ...) { override BOOL NewMsgProc(HWND hWnd, UINT uID, WPARAM wParam, LPARAM lParam, ref LRESULT lResult) { foreach(mapping; Mappings) { if(mapping.matches(uID)) mapping.executeAction(); } } } Change MessageMap to return the result of the mapping.executeAction just like "return lResult;" in the original C++. template MessageMap(Mappings ...) { override BOOL NewMsgProc(HWND hWnd, UINT uID, WPARAM wParam, LPARAM lParam, ref LRESULT lResult) { foreach(mapping; Mappings) { if(mapping.matches(uID)) { lResult = mapping.executeAction(); return cast(BOOL)lResult; } } } } I think it's ok to use mixins as you're desribing, but why do you need to do it that way? Regan
Sep 21 2007
parent reply BLS <nanali nospam-wanadoo.fr> writes:
Regan Heath schrieb:
 BLS wrote:
 Regan Heath schrieb:
 Henning Hasemann wrote:


I don't understand. What doesn't the code Henning posted do, that you need it to do??

Probabely, because I am not genius... :-( I 'd better read it twice! Just one question : It seems that you use template overloading, or do I miss something. In other words : Can I use template overloading like function overloading ? Many thanks for your efforts, Regan and Henning ! Bjoern
 class Foo {
   void foo() {
     writefln("foo called");
   }
   void bar() {
     writefln("bar called");
   }
 
   mixin MessageMap!(
     OnClose!(foo),
     OnRange!(1, 3, bar)
   );
 }
 
 expands to:
 
 class Foo {
   void foo() {
     writefln("foo called");
   }
   void bar() {
     writefln("bar called");
   }
 
   void newMsgProc(uint uID) {      //expands just like "BEGIN_MSG_MAP"
      foreach(mapping; Mappings) {  //loops 2x
        if(mapping.matches(uID))    //just like "if (uID == WM_CLOSE)"
          mapping.executeAction();  //just like "vfunc();"
      }
   }
 }
 
 Change MessageMap to expand to the function fignature you want, i.e.
 
 template MessageMap(Mappings ...) {
   override BOOL NewMsgProc(HWND hWnd, UINT uID, WPARAM wParam, LPARAM 
 lParam, ref LRESULT lResult) {
      foreach(mapping; Mappings) {
        if(mapping.matches(uID))
          mapping.executeAction();
      }
   }
 }
 
 Change MessageMap to return the result of the mapping.executeAction just 
 like "return lResult;" in the original C++.
 
 template MessageMap(Mappings ...) {
   override BOOL NewMsgProc(HWND hWnd, UINT uID, WPARAM wParam, LPARAM 
 lParam, ref LRESULT lResult) {
      foreach(mapping; Mappings) {
        if(mapping.matches(uID)) {
          lResult = mapping.executeAction();
          return cast(BOOL)lResult;
        }
      }
   }
 }
 
 I think it's ok to use mixins as you're desribing, but why do you need 
 to do it that way?
 
 Regan

Probabely, because I am not genius... :-( I 'd better read it twice! Just one question : It seems that you use template overloading, or do I miss something. In other words is template overloading legal ? Many thanks for your efforts, Regan and Henning ! Bjoern
Sep 21 2007
next sibling parent Regan Heath <regan netmail.co.nz> writes:
BLS wrote:
 Regan Heath schrieb:
 BLS wrote:
 Regan Heath schrieb:
 Henning Hasemann wrote:


I don't understand. What doesn't the code Henning posted do, that you need it to do??

Probabely, because I am not genius... :-( I 'd better read it twice!

Join the club ;)
 Just one question : It seems that you use template overloading, or do I 
 miss something. 

The mixin mixes in a function "newMsgProc" which should overload a base class function of the same signature (whether mixed in also or typed). I think this works, but I am not 100% certain. The docs do say: "Templates cannot be used to add non-static members or functions to classes" on the templates page, but I'm not sure if that applies to "template mixins" too, or what.
 In other words : Can I use template overloading like
 function overloading ?

I think so, however you can't mix template function and function overloading, i.e. class Foo { void foo(T)(T arg) { } void foo(float arg) { } } But Walter plans to make this work I believe. Regan
Sep 21 2007
prev sibling parent BLS <nanali nospam-wanadoo.fr> writes:
Henning Hasemann schrieb:
 Thanks for all the compliments :)
 
 
 Just one question : It seems that you use template overloading, or do
 I miss something. In other words : Can I use template overloading
 like function overloading ?

Somehow you can do stuff like this for example: template Foo(int n, T) { // some stuff } template Foo(T) { // something else } You can even define templates differently for different types, but thats called "specialisation" not overloading. But I dont use such a thing here. What I do is defining a few templated structs and the structs (not instances of them, the actual type!) are given to MessageMap which calls the static functions. So technically, OnClose!(foo) and OnRange!(1, 3, bar) are *types* that contain aliases (think of compile time references) to the methods you want to call. The "mixin MessageMap!(...)" simply adds a new method to your class. Note that because it is run over types, the "foreach(mapping; Mappings) { .. }" is done at compile time, ie its body is repeated for every type (I called them Mapping's here), so all runtime overhead you have are the ifs that evaluate to false. If you have further questions, dont hesitate to ask :)

I am afraid that will happen :-)
 
 Henning
 

Just to show you what I am translating : http://www.beyondata.com/pwc.html A really smart GUI. Download if you like the Pretty WinApi Class, it is a small one. (I need as GUI toolkit for my IDE project) However, thanks to your and Regan's help I am ready to give it a go. Many thanks ! Bjoern
Sep 21 2007
prev sibling next sibling parent Henning Hasemann <hhasemann web.de> writes:
Thanks for all the compliments :)


 Just one question : It seems that you use template overloading, or do
 I miss something. In other words : Can I use template overloading
 like function overloading ?

Somehow you can do stuff like this for example: template Foo(int n, T) { // some stuff } template Foo(T) { // something else } You can even define templates differently for different types, but thats called "specialisation" not overloading. But I dont use such a thing here. What I do is defining a few templated structs and the structs (not instances of them, the actual type!) are given to MessageMap which calls the static functions. So technically, OnClose!(foo) and OnRange!(1, 3, bar) are *types* that contain aliases (think of compile time references) to the methods you want to call. The "mixin MessageMap!(...)" simply adds a new method to your class. Note that because it is run over types, the "foreach(mapping; Mappings) { .. }" is done at compile time, ie its body is repeated for every type (I called them Mapping's here), so all runtime overhead you have are the ifs that evaluate to false. If you have further questions, dont hesitate to ask :) Henning -- GPG Public Key: http://keyserver.ganneff.de:11371/pks/lookup?op=get&search=0xDDD6D36D41911851 Fingerprint: 344F 4072 F038 BB9E B35D E6AB DDD6 D36D 4191 1851
Sep 21 2007
prev sibling parent Henning Hasemann <hhasemann web.de> writes:
 Just to show you what I am translating :
 http://www.beyondata.com/pwc.html
 A really smart GUI.
 Download if you like the Pretty WinApi Class, it is a small one.
 (I need as GUI toolkit for my IDE project)

Thanks but as a linux user and for-linux-and-windows coder I dont have a real use for a win-only gui lib... I'd be more happy about a good gtk wrapper with active development. Henning -- GPG Public Key: http://keyserver.ganneff.de:11371/pks/lookup?op=get&search=0xDDD6D36D41911851 Fingerprint: 344F 4072 F038 BB9E B35D E6AB DDD6 D36D 4191 1851
Sep 21 2007