Skip to content

Instantly share code, notes, and snippets.

@vporton
Last active August 7, 2020 03:19
Show Gist options
  • Save vporton/1b17b2c60e2cf94a4cab0f2b8fc03c5a to your computer and use it in GitHub Desktop.
Save vporton/1b17b2c60e2cf94a4cab0f2b8fc03c5a to your computer and use it in GitHub Desktop.

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment