Various stuff for working with templates.

Boost License 1.0.
Denis Shelomovskij

template  Inst(alias Template, A...)

Instantiate a template Template using arguments A.

import std.traits: PointerTarget;

static assert(is(Inst!(PointerTarget, int*) == int));

template  Template(alias Pred, int argumentsCount, EnumType = void) if (argumentsCount >= -1)
template  UnaryTemplate(alias Pred, EnumType = void)
template  BinaryTemplate(alias Pred, EnumType = void)

Create template from a string Pred. If Pred isn't a string, alises itself to Pred.

If argumentsCount is -1 created template will accept any number of arguments, otherwise it will expect argumentsCount arguments.

If EnumType is void created template may be an alias or an enum, otherwise it will be an enum of type EnumType.

Created template can access its aruments as a generic tuple with Args.

If argumentsCount is 1 or 2 created template can access its first argument with a if it is an value, with T if it is a type and with A otherwise.

If argumentsCount is 2 created template can access its second argument with b if it is an value, with U if it is a type and with B otherwise.

UnaryTemplate is a convinient way to create a template with one argument (argumentsCount is 1).

BinaryTemplate is a convinient way to create a template with two arguments (argumentsCount is 2).

static assert(Inst!(UnaryTemplate!`__traits(isUnsigned, T)`, uint));
static assert(is(Inst!(UnaryTemplate!`T[]`, int) == int[]));
static assert(Inst!(UnaryTemplate!`a == 5`, 5));
static assert(Inst!(BinaryTemplate!`a == 1 && b == 2`, 1, 2));
static assert(Inst!(BinaryTemplate!`a + U.sizeof`, 1, int) == 5);
static assert(PackedGenericTuple!(Inst!(Template!(`Args`, -1), "x", int)).equals!("x", int));

template  unaryPred(alias pred)
template  binaryPred(alias pred)

Using  unaryPred or binaryPred is a convinient way to create a template with one or two arguments respectively which is an enum of type bool.

It is equal to instantiating Template with corresponding argumentsCount and bool as EnumType.

static assert(Inst!(unaryPred!`__traits(isUnsigned, T)`, uint));
static assert(Inst!(binaryPred!`a == U.sizeof`, 4, int));

template  notTemplate(alias template_)

Create predicate template returning !template_.

import std.traits: isPointer;

alias notPointer = notTemplate!isPointer;
static assert( notPointer! int );
static assert(!notPointer!(int*));

alias toBoolTemplate = notTemplate!notTemplate;
static assert(Inst!(toBoolTemplate!isPointer, int*));
template get5() { enum get5 = 5; }
static assert(Inst!(toBoolTemplate!get5) == true);

template  andTemplates(templates...)

Create predicate template returning true iff there are no templates or all templates return non-zero.

import std.traits: isIntegral, isSigned;

alias isSignedIntegral = andTemplates!(isIntegral, isSigned);
static assert( allTuple!(isSignedIntegral,  int,  short, long));
static assert(!anyTuple!(isSignedIntegral, uint, ushort, ulong));

alias isShort = andTemplates!(isSignedIntegral, unaryPred!`is(T == short)`);
static assert( isShort!short);
static assert(!anyTuple!(isShort, int, long, uint, ushort, ulong));

template  orTemplates(templates...)

Create predicate template returning true iff any template of templates return non-zero (i.e. returning false if there are no templates).

import std.traits: isIntegral, isFloatingPoint;

alias isIntegralOrFloating = orTemplates!(isIntegral, isFloatingPoint);
static assert( allTuple!(isIntegralOrFloating, int,  short, long, float, double));
static assert(!anyTuple!(isIntegralOrFloating, bool, char));

alias isIntegralOrFloatingOrChar = orTemplates!(isIntegralOrFloating, unaryPred!`is(T == char)`);
static assert( allTuple!(isIntegralOrFloatingOrChar, int, short, long, float, double, char));
static assert(!isIntegralOrFloatingOrChar!bool);

template  BindTemplate(alias Template, BindArgs...)

Binds template arguments.

  • use args[i] or arg!i to refer i-th argument;
  • use args[$ - i] to refer arguments from the end (also args[$ + i] can be used for negative i);
  • use args[a .. b] or argsRange!(a, b) to refer arguments from a-th up to and excluding b-th;
  • use argsToEnd!n to refer arguments from n-th argument up to the end;
  • use allArgs to refer all arguments.

import unstd.traits;

static assert(is(Inst!(BindTemplate!(CommonType, long, allArgs), int) == long));
static assert(!Inst!(BindTemplate!(isImplicitlyConvertible, args[0], int), long));
static assert( Inst!(BindTemplate!(isImplicitlyConvertible, int  , arg!0), long));

alias UnqualAll = BindTemplate!(MapTuple, Unqual, allArgs);
static assert(is(UnqualAll!(const(int), immutable(bool[])) == TypeTuple!(int, immutable(bool)[])));
Known Bugs
Currently there is no support for args[a .. $] because of compiler limitations.

template  Bind(string fmt)

Binds template arguments using format string.

  • use %i to refer i-th argument;
  • use %* to refer all arguments;
  • use %% for a % symbol.

import unstd.traits;

mixin Bind!q{ CommonTypeToLong = CommonType!(long, %*) };
static assert(is(CommonTypeToLong!int == long));

mixin Bind!q{ isImplicitlyConvertibleToInt = isImplicitlyConvertible!(%0, int) };
static assert(!isImplicitlyConvertibleToInt!long);

mixin Bind!q{ isImplicitlyConvertibleFromInt = isImplicitlyConvertible!(int, %0) };
static assert( isImplicitlyConvertibleFromInt!long);

mixin Bind!q{ UnqualAll = MapTuple!(Unqual, %*) };
static assert(is(UnqualAll!(const(int), immutable(bool[])) == TypeTuple!(int, immutable(bool)[])));