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