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