On Friday, 28 February 2020 at 09:12:38 UTC, Simen Kjærås wrote:
On Friday, 28 February 2020 at 06:12:37 UTC, Виталий Фадеев
wrote:
Searching solution for idea !
For whatever reason, it seems my attempts at answering this
earlier has disappeared into the void. Here:
import core.sys.windows.windows;
import std.stdio;
class Base {
LRESULT On(UINT message, WPARAM wParam, LPARAM lParam) {
switch (message) {
case WM_KEYDOWN:
return tryCall!"OnWM_KEYDOWN"(wParam, lParam);
default:
}
return 0;
}
auto tryCall(string name, Args...)(Args args) {
import std.meta;
alias This = typeof(this);
alias module_ = __traits(parent, This);
enum isSubclass(T...) = is(T[0] : This);
alias getModuleMember(string name) =
__traits(getMember, module_, name);
enum hasMethod(T) = __traits(hasMember, T, name);
// Get every member in this module
enum memberNames = __traits(allMembers, module_);
alias members = staticMap!(getModuleMember,
memberNames);
// Filter away anything that isn't derived from Base
alias subclasses = Filter!(isSubclass, members);
// Get rid of anything that doesn't have a method with
the correct name
alias subclassesWithMethod = Filter!(hasMethod,
subclasses);
// Sort them so you get the most derived types first
alias Types = DerivedToFront!subclassesWithMethod;
// Check for each type if the `this` is an instance of
that specific one
static foreach (T; Types) {
if (cast(T)this !is null) {
// And look up that method and call it.
return __traits(getMember, cast(T)this,
name)(args);
}
}
// If `this` is not one of the types with that method,
return some default value
return 0;
}
}
class Button : Base {
LRESULT OnWM_KEYDOWN(WPARAM wParam, LPARAM lParam) {
writeln("WM_KEYDOWN");
return 0;
}
}
unittest {
Base b1 = new Base();
Base b2 = new Button();
writeln("Base:");
b1.On(WM_KEYDOWN, 0, 0);
writeln("Button:");
b2.On(WM_KEYDOWN, 0, 0);
}
Now, this only works for subclasses defined in the same module.
A possibly better solution would be interfaces:
import core.sys.windows.windows;
import std.stdio;
class Base {
LRESULT On(UINT message, WPARAM wParam, LPARAM lParam) {
switch (message) {
case WM_KEYDOWN:
if (cast(IKeyDown)this) {
return
(cast(IKeyDown)this).OnWM_KEYDOWN(wParam, lParam);
}
default:
}
return 0;
}
}
interface IKeyDown {
LRESULT OnWM_KEYDOWN(WPARAM wParam, LPARAM lParam);
}
class Button : Base, IKeyDown {
LRESULT OnWM_KEYDOWN(WPARAM wParam, LPARAM lParam) {
writeln("WM_KEYDOWN");
return 0;
}
}
unittest {
Base b1 = new Base();
Base b2 = new Button();
writeln("Base:");
b1.On(WM_KEYDOWN, 0, 0);
writeln("Button:");
b2.On(WM_KEYDOWN, 0, 0);
}
--
Simen
Yes. Thank !
I read it.
Problem is - OS has many messages + user messages... It mean what
interfaces like IKeyDown must me declared. All. Dream on write
less code...
Some like code generation. In message dispatcher. Like this:
import core.sys.windows.windows;
import std.stdio;
import std.traits;
template canOn( T, M )
{
enum string callbackName = "On" ~ __traits( identifier, M
);
static if ( __traits( hasMember, T, callbackName ) )
enum canOn = isCallable!( __traits( getMember, T,
callbackName ) );
else
enum canOn = false;
}
void maybeOn( T, alias M )( T o, M message )
{
enum string callbackName = "On" ~ __traits( identifier, M
);
static if ( canOn!(T, M) )
__traits( getMember, T, callbackName )();
}
void On( T, alias M )( T o, M message )
{
o.maybeOn( message );
}
class Base
{
void Send( T, alias M )( T o, M message )
{
// generate code in dispatcher
// if ( canOn!( T, M ) )
// writeCode(
// q{
// if ( message == WM_KEYUP )
// o.OnWM_KEYUP();
// }
// );
o.On( message );
}
}
class A : Base
{
void OnWM_KEYUP()
{
writeln( "A.OnKey()" );
}
}
void main()
{
auto a = new A();
a.Send( a, WM_KEYUP );
}
Here I have compile error... at
void On( T, alias M )( T o, M message )
Now I reading Template doc for up skill...
Thank!