Instantiate

Instantiates the given template with the given arguments and evaluates to the result of that template.

This is used to work around some syntactic limitations that D has with regards to instantiating templates. Essentially, D requires a name for a template when instantiating it (be it the name of the template itself or an alias to the template), which causes problems when you don't have that.

Specifically, if the template is within an AliasSeq - e.g. Templates[0]!Args - or it's the result of another template - e.g Foo!Bar!Baz - the instantiation is illegal. This leaves two ways to solve the problem. The first is to create an alias, e.g.

alias Template = Templates[0];
enum result = Template!Args;

alias Partial = Foo!Bar;
alias T = Partial!Baz;

The second is to use Instantiate, e.g.

enum result = Instantiate!(Templates[0], Args);

alias T = Instiantiate!(Foo!Bar, Baz);

Of course, the downside to this is that it adds an additional template instantiation, but it avoids creating an alias just to be able to instantiate a template. So, whether it makes sense to use Instantiate instead of an alias naturally depends on the situation, but without it, we'd be forced to create aliases even in situations where that's problematic.

alias Instantiate(alias Template, Args...) = Template!Args

Examples

import phobos.sys.traits : ConstOf, isImplicitlyConvertible, isSameType, isInteger;

alias Templates = AliasSeq!(isImplicitlyConvertible!int,
                            isSameType!string,
                            isInteger,
                            ConstOf);

// Templates[0]!long does not compile, because the compiler can't parse it.

static assert( Instantiate!(Templates[0], long));
static assert(!Instantiate!(Templates[0], string));

static assert(!Instantiate!(Templates[1], long));
static assert( Instantiate!(Templates[1], string));

static assert( Instantiate!(Templates[2], long));
static assert(!Instantiate!(Templates[2], string));

static assert(is(Instantiate!(Templates[3], int) == const int));
static assert(is(Instantiate!(Templates[3], double) == const double));
template hasMember(string member)
{
    enum hasMember(T) = __traits(hasMember, T, member);
}

struct S
{
    int foo;
}

// hasMember!"foo"!S does not compile,
// because having multiple ! arguments is not allowed.

static assert( Instantiate!(hasMember!"foo", S));
static assert(!Instantiate!(hasMember!"bar", S));

Instantiate also allows us to do template instantations via templates that take other templates as arguments.

import phobos.sys.traits : isInteger, isNumeric, isUnsignedInteger;

alias Results = Map!(ApplyRight!(Instantiate, int),
                     isInteger, isNumeric, isUnsignedInteger);

static assert([Results] == [true, true, false]);

See Also

Meta