Template Constraints

A template constraint is simply an if condition that comes before the function body. Unlike template specialisations which only allow us to specify that a template type must inherit from some other type, template constraints come with the flexibility of if statements. We can use complex expressions as constraints and we can combine them using || or &&.

Demo

To understand template constraints better, let’s look at the code in demo/template-constraints/template_constraints.d. First, let’s look at the sub function. Its constraint (if (is(T == int) || is(T == real) || is(T == double))) checks whether the type of the arguments is int, real or double. The unittest that calls this function specifies that sub("yes", "no") should not compile.

Now let’s take a look at a more interesting example. returnIfPrimeTemplate checks if its template argument is a prime number. This means that isPrime(num) is evaluated at compile time. This procedure is called Compile Time Function Evaluation (CTFE). We will dive deeper into this topic later in this session. Until then, CTFE means precisely what its name implies: the compiler evaluates the result of a function whose parameters are known at compile time.

Quiz 1

Logger

While template specialisations work just fine for bool and string logs, they do not allow us to aggregate all numeric types into a signle function.

Quiz 2

What we need to be able to log numeric types is a template constraint.

Now that you understand template constraints, find an appropriate template trait and use it to create a log function for numeric data types. You can convert them to strings using std.conv.to, as shown in the section on UFCS.