In D language we cannot construct an object of a template argument type in a template, as shown by the following example:
class Constructor(Result, Params...) {
const(Result) create(Params params) {
return new Result(params);
}
}
void main() {
class X { }
auto a = new Constructor!X;
auto p = a.create();
}
Trying to compile, we get:
a.d(3): Error: outer function context of D main is needed to new nested class a.main.X
a.d(9): Error: template instance `a.Constructor!(X)` error instantiating
It is because create()
does not know (and cannot know) from where it was called but an object must know its context in D.
Is there any possible way to change D language to somehow support programs like the above? I do not know. However there is a workaround: Use lambda function as template arguments to construct objects of user-provided kind in templates:
import std.traits;
class Constructor(alias Function) {
const(ReturnType!Function) create(Parameters!Function params) {
return Function(params);
}
}
void main() {
class X {
this(float x, float y) { } // This construct does nothing.
}
auto a = new Constructor!((float x, float y) => new X(x, y));
auto p = a.create(7.1, 3.2);
}
Here we create a lambda-function (float x, float y) => new X(x, y)
and pass it to the template. The rest template magic is done by the standard library module std.traits
, namely the templates ReturnType
which retrieves return type of the function (X
in our case) and Parameters
which retrieves a tuple (compile time fixed-length sequence) of the parameter types of the function.