Call method if declared only

Виталий Фадеев vital.fadeev at gmail.com
Sat Feb 29 16:04:02 UTC 2020


On Friday, 28 February 2020 at 12:21:41 UTC, Simen Kjærås wrote:
> On Friday, 28 February 2020 at 10:33:11 UTC, Виталий Фадеев 
> wrote:
>> Thanks all !
>> I happy !
>> Check this one:
>>     void On( T, M )( T o, M message )
>>     {
> [snip]
>>     void main()
>>     {
>>         auto a = new A();
>>         a.Send( a, WM_KEYUP );
>>         a.Send( a, WM_KEYDOWN );
>>     }
>
> That does mostly work, but fails for this code:
>
> void main()
> {
>     Base a = new A();
>     a.send( a, WM_KEYUP );
> }
>
> Basically, whenever you assign a derived to a base, this 
> solution doesn't work, because T will be Base, not A.
>
> I enjoyed with the previous code, so I wrote the code necessary 
> to handle any WM_ message:
>
> import core.sys.windows.windows;
> import std.stdio;
> import std.meta;
>
> template startsWith(string prefix) {
>     enum startsWith(string s) = s.length >= prefix.length && 
> s[0..prefix.length] == prefix;
> }
>
> enum getMessageValue(string s) = __traits(getMember, 
> core.sys.windows.winuser, s);
>
> // Get the all the WM_ messages
> alias messageNames = Filter!(startsWith!"WM_", 
> __traits(allMembers, core.sys.windows.winuser));
> alias messageValues = NoDuplicates!(staticMap!(getMessageValue, 
> messageNames));
>
> class Base {
>     LRESULT On(UINT message, WPARAM wParam, LPARAM lParam) {
>         switch (message) {
>             foreach (msg; messageValues) {
>                 case msg:
>                     if (auto that = 
> cast(IMessageHandler!msg)this) {
>                         return that.handle(wParam, lParam);
>                     }
>                     break;
>             }
>             default:
>         }
>         return 0;
>     }
> }
>
> interface IMessageHandler(alias msg) {
>     mixin("LRESULT On"~__traits(identifier, msg)~"(WPARAM 
> wParam, LPARAM lParam);");
>     alias handle = mixin("On"~__traits(identifier, msg));
> }
>
> class Button : Base, IMessageHandler!WM_KEYDOWN, 
> IMessageHandler!WM_SETTINGCHANGE {
>     LRESULT OnWM_KEYDOWN(WPARAM wParam, LPARAM lParam) {
>         writeln("WM_KEYDOWN");
>         return 0;
>     }
>     LRESULT OnWM_SETTINGCHANGE(WPARAM wParam, LPARAM lParam) {
>         writeln("WM_SETTINGCHANGE");
>         return 0;
>     }
> }
>
> unittest {
>     Base b1 = new Base();
>     Base b2 = new Button();
>
>     writeln("Base:");
>     // None of these will print anything, as Base doesn't 
> handle them
>     b1.On(WM_KEYDOWN, 0, 0);
>     b1.On(WM_SETTINGCHANGE, 0, 0);
>     b1.On(WM_DRAWITEM, 0, 0);
>     writeln("Button:");
>     b2.On(WM_KEYDOWN, 0, 0);
>     b2.On(WM_SETTINGCHANGE, 0, 0);
>     // This will print nothing, as Button doesn't handle that 
> message.
>     b2.On(WM_DRAWITEM, 0, 0);
> }
>
> --
>   Simen

Thank!

Today version is:

import core.sys.windows.windows;
import std.stdio;
import std.traits;
import std.conv : to;
import std.algorithm.searching : startsWith;


mixin template Eventable()
{
     override
     void On( UINT message )
     {
         // generate code in dispatcher
         // get AllMembers()
         //   filter OnABC (ex: OnWM_KEYUP)
         //   on each
         //   writeCode(
         //        if ( message == WM_KEYUP ) this.OnWM_KEYUP();
         //   );

         foreach( methodName; __traits( allMembers, typeof( this ) 
) )
         {
             static if ( methodName.startsWith( "On" ) && 
methodName.length >= 3 )
             {
                 mixin (
                     "if ( message == " ~ methodName[2..$] ~ " ) " 
~ "this." ~ methodName ~ "();"
                 );
             }
         }
     }
}


void Send( T, M )( T o, M message )
{
     o.On( message );
}


class Base
{
     void On( UINT message )
     {
         writeln( "Base.On() // default" );
     };
}


class A : Base
{
     mixin Eventable;

     void OnWM_KEYUP()
     {
         writeln( "A.OnWM_KEYUP()" );
     }

     void OnWM_KEYDOWN()
     {
         writeln( "A.OnWM_KEYDOWN()" );
     }
}


void main()
{
     auto a = new A();
     a.Send( WM_KEYUP );   // A

     auto c = cast(Base)a; // Base
     c.Send( WM_KEYUP );
}

// output:
// A.OnWM_KEYUP()
// A.OnWM_KEYUP()



More information about the Digitalmars-d-learn mailing list