D Medium · Lesson 1 · On the house

Template constraints and static if

Restrict templates with if constraints, branch at compile time with static if, and is expressions. Lesson 1 is free — on the house.

Lessons · D Medium · Lesson 1 of 10 · On the house

Template constraints and static if

Restrict templates with if constraints, branch at compile time with static if, and is expressions.

Illustration for D
Lesson 1 is on the house.

A template constraint is an if (...) after the parameter lists: T mean(T)(T[] xs) if (isFloatingPoint!T). If it is false, that overload is simply not a candidate, so callers get a clear "no match" error instead of a failure deep inside the body.

std.traits supplies predicates: isIntegral, isFloatingPoint, isSomeString, isNumeric; std.range supplies isInputRange, isRandomAccessRange, ElementType.

Two overloads with mutually exclusive constraints let one name dispatch by type category.

static if (cond) chooses code at compile time inside a function or type; the untaken branch is not compiled, so it may contain code that would not type-check for this T.

is(T == string) tests type equality; is(T : long) tests implicit convertibility; is(typeof(expr)) tests whether an expression compiles at all.

static assert(cond, "msg") stops compilation with a message, the compile-time counterpart of assert.

constraints

import std.stdio, std.traits, std.range, std.algorithm;

auto mean(R)(R r) if (isInputRange!R && isNumeric!(ElementType!R))
{
    double total = 0;
    size_t n;
    foreach (x; r) { total += x; ++n; }
    return total / n;
}

string describe(T)(T x)
{
    static if (isIntegral!T)
        return "int-like " ~ (x % 2 ? "odd" : "even");
    else static if (isSomeString!T)
        return "text of " ~ (cast(char)('0' + x.length)) ~ " chars";
    else static if (is(typeof(x.length)))
        return "has length";
    else
        return "other " ~ T.stringof;
}

void main()
{
    writeln(mean([1, 2, 3, 4]), " ", mean(iota(1, 4).map!(x => x * 1.5)));
    writeln(describe(7), " | ", describe("abc"), " | ", describe([1, 2]), " | ", describe(2.5));
    writeln(is(int : long), " ", is(long : int), " ", is(typeof(mean(["a"]))));
    static assert(isIntegral!ubyte);
}
Match this when you type.

Quiz

What happens when a template constraint is false for a call?

Quiz

Is the untaken branch of static if compiled?

Quiz

What does is(typeof(expr)) test?

Quiz

What does is(long : int) evaluate to?

Check

Match the still for: Template constraints and static if.

Open-book: the answers are on this page. Pass every quiz and check (5) to mark the lesson done. This visit: 0/5.