Map type to class instance at compile-time
Ali Çehreli via Digitalmars-d-learn
digitalmars-d-learn at puremagic.com
Wed Oct 26 11:19:33 PDT 2016
On 10/26/2016 10:48 AM, pontius wrote:
> Apologies for the long post or stupid questions, I only started to learn
> D today.
Looking at what you've achieved in one day, we really need you! :)
> I have a use case where various types (A, B, C) need to be associated
> with instances of different classes (ManagerA, ManagerB, ManagerC). A
> certain object (globalManager) should redirect operations on those types
> to their respective managers at compile-time. I intend to use it in the
> following way:
>
> class GlobalManager(TypeToManagerMapping) {
> public void process(T)(T t) {
> // Must be resolved at compile-time
> TypeToManagerMapping.getManagerForType(T).process(t);
> }
> }
>
> // All these types can be completely unrelated, i.e. no base classes
> struct A {}
> alias ManagerA = DefaultManager!(A)
> struct B {}
> alias ManagerB = DefaultManager!(B)
> struct C {}
> alias ManagerC = SomeCustomManager;
>
> // Calls to globalManager should be redirected to these at compile-time
> auto mgrA = new ManagerA();
> auto mgrB = new ManagerB();
> auto mgrC = new ManagerC();
>
> // This is my problem, see below
> alias TypeToManagerMapping = ...;
>
> // Pass the mapping as a template parameter so that it can be resolved
> at compile-time
> auto globalManager = new GlobalManager!(TypeToManagerMapping)();
>
> // The following is the module user's code.
> // The user may not be aware of mgrA, mgrB, etc, only of globalManager
>
> A a = A();
> B b = B();
> C c = C();
>
> // Redirection to managers in the following operations
> // must be resolved at compile-time
>
> // Should turn into mgrA.process(a), etc
> globalManager.process(a);
> globalManager.process(b);
> globalManager.process(c);
void report(M, T)() {
import std.stdio : writefln;
writefln("%s is managing an object of %s", M.stringof, T.stringof);
}
class DefaultManager(T) {
void manage(T t) {
report!(typeof(this), T);
}
}
class SomeCustomManager {
void manage(C c) {
report!(SomeCustomManager, C);
}
}
struct A {}
alias ManagerA = DefaultManager!(A);
struct B {}
alias ManagerB = DefaultManager!(B);
struct C {}
alias ManagerC = SomeCustomManager;
/*/ You can use this:
alias TypeToManagerMapping = AliasSeq!(A, ManagerA,
B, ManagerB,
C, ManagerC);
However, if you already have symbolic mapping from T to ManagerT, you
can use string mixins as well
*/
template ManagerRegistrationFor(T) {
// Just a couple of convenience functions
string managerType() { return "Manager" ~ T.stringof; }
string managerName() { return "mng" ~ T.stringof; }
// This is the manager object
mixin(managerType() ~ ' ' ~ managerName() ~ ';');
// This is the initialization of it
static this() {
mixin(managerName() ~ `= new ` ~ managerType() ~ ';');
}
void manage(T obj) {
// Dispatches to the manager
mixin(managerName() ~ ".manage(obj);");
}
}
struct GlobalManager {
void process(T)(T t) {
manage(t);
}
}
GlobalManager globalManager;
mixin ManagerRegistrationFor!A;
mixin ManagerRegistrationFor!B;
mixin ManagerRegistrationFor!C;
/* The above could be specified with an AliasSeq (uncompiled):
alias ManagedTypes = AliasSeq!(A, B, C);
This loop can be inside a template like RegisterManagedTypes
foreach (T; ManagedTypes) {
mixin ManagerRegistrationFor!T;
}
And then:
mixin RegisterManagedTypes;
*/
void main() {
A a = A();
B b = B();
C c = C();
globalManager.process(a);
globalManager.process(b);
globalManager.process(c);
}
There are different approaches but I think the solution above achieves
what you want:
DefaultManager!(A) is managing an object of A
DefaultManager!(B) is managing an object of B
SomeCustomManager is managing an object of C
Ali
More information about the Digitalmars-d-learn
mailing list