Template Constraints and Variadic Templates

25.1 Template Constraints

Constraints pick overloads and give clearer errors. Use static assert inside for custom messages.

import std.traits, std.range;

T sumAll(T)(T[] arr) if (isNumeric!T)
{
    T total = 0;
    foreach (x; arr) total += x;
    return total;
}

auto firstOrDefault(R)(R r, ElementType!R def) if (isInputRange!R)
{
    return r.empty ? def : r.front;
}

void process(T)(T x)
if (is(typeof(x.serialize()) : string))    // structural constraint: "has serialize() returning string"
{
}

25.2 Variadic Templates and AliasSeq

import std.meta;

void printAll(Args...)(Args args)
{
    foreach (i, arg; args)                 // unrolled at compile time
        writefln("%d: %s (%s)", i, arg, typeof(arg).stringof);
}
printAll(1, "two", 3.0);

alias Types = AliasSeq!(int, string, double);
alias Numbers = Filter!(isNumeric, Types);       // (int, double)
alias Ptrs = staticMap!(Ptr, Types);
static assert(staticIndexOf!(string, Types) == 1);
enum allInts = allSatisfy!(isIntegral, int, long);

auto tupleSum(T...)(T args) { typeof(args[0]) s = 0; foreach (a; args) s += a; return s; }

25.3 is Expressions

static if (is(T == int)) {}                  // exact type
static if (is(T : long)) {}                  // implicitly convertible
static if (is(T == U[], U)) {}               // pattern match: T is an array of some U
static if (is(T == class)) {}                // kind: class, struct, interface, enum, union, function, delegate
static if (is(typeof(T.init.foo()))) {}      // does this expression compile?
static if (is(T : Base)) {}
static if (__traits(compiles, x.foo())) {}