The Shortcut Syntax

The shortcut syntax of templates is explained in this lesson.

You saw the power and convenience of templates in the templates chapter. A single templated definition of an algorithm or a data structure can effectively be used for multiple types.

The earlier chapter covered only the most common uses of templates, including function, struct, and class templates and their uses with type template parameters. In this chapter, we cover templates in more detail. Before going further, we recommend that you review the following templates summary.

The shortcut syntax

In addition to being powerful, D templates are easy to define and use, and they are very readable. Defining a function, struct, or class template is as simple as providing a template parameter list:

T twice(T)(T value) {
    return 2 * value;
}

class Fraction(T) {
    T numerator;
    T denominator;
    
    // ...
}

Template definitions like the ones above take advantage of D’s shortcut template syntax.

In their full syntax, templates are defined by the template keyword. The equivalents of the two template definitions above are below:

template twice(T) {
    T twice(T value) {
        return 2 * value;
    }
}

template Fraction(T) {
    class Fraction {
        T numerator;
        T denominator;
        // ...
    } 
}

Although most templates are defined by the shortcut syntax, the compiler always uses the full syntax. We can imagine the compiler applying the following steps to convert a shortcut syntax to its full form behind the scenes:

  1. Wrap the definition with a template block.

  2. Give the same name to that block.

  3. Move the template parameter list to the template block.

The full syntax that is arrived at after these steps is called eponymous template, which the programmer can define explicitly. We explain eponymous templates later.

Template namespace

It is possible to have more than one definition inside a template block. The following template contains both a function and a struct definition:

template MyTemplate(T) {
    T foo(T value) {
        return value / 3;
    }
struct S {
    T member; 
    }
}

Instantiating the template for a specific type instantiates all of the definitions inside the block. The following code instantiates the template for int and double:

Get hands-on with 1000+ tech skills courses.