Map type to class instance at compile-time
pontius via Digitalmars-d-learn
digitalmars-d-learn at puremagic.com
Wed Oct 26 10:48:15 PDT 2016
Apologies for the long post or stupid questions, I only started
to learn D today.
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);
So, I need to map a type (e.g. A) to an instance (e.g. mgrA). I
have managed to implement a compile-time map from type to value
(by the way, how do I get rid of TValue argument in
TypeValuePair? it can be deduced, but I failed to get it working
with an eponymous template):
struct TypeValuePair(TKey_, TValue, TValue value_) {
alias TKey = TKey_;
static const TValue value = value_;
}
struct StaticMap(THead, Args...) {
template get(T) {
static if (Args.length < 0) {
static assert(false, "StaticMap does not contain this key");
} else static if (is(T == THead.TKey)) {
alias get = THead.value;
} else {
alias get = StaticMap!(Args).get!(T);
}
}
}
This works nicely for mapping types to literal values:
alias TypeMap = StaticMap!(
TypeValuePair!(string, string, "a string"),
TypeValuePair!(int, string, "an int"),
TypeValuePair!(bool, string, "a bool")
);
writeln(TypeMap.get!(int));
But fails with "variable cannot be read at compile-time" when I
try to pass a class instance in there:
alias TypeMap = StaticMap!(
TypeValuePair!(A, ManagerA, mgrA)
);
TypeMap.get!(A).process(a);
So, how do I resolve type-to-instance mapping at compile-time so
that my user only needs to call globalManager and not know
anything about individual managers?
I could easily do this with typeid() calls, but the solution must
be purely compile-time (for learning purposes; let's say my code
is performance-critical and the lookup would take considerable
amount of time).
More information about the Digitalmars-d-learn
mailing list