> For the complete documentation index, see [llms.txt](https://docs.perception.cx/perception/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.perception.cx/perception/enma-lang/language-guide/templates.md).

# Templates

Compile-time monomorphization: each unique type combination produces a separate concrete implementation.

## Template Structs

```cpp
template<typename T>
struct Pair {
    T first;
    T second;
    Pair(T a, T b) { first = a; second = b; }
    T sum() { return first + second; }
}

Pair<int32> p = Pair<int32>(10, 20);
println(std::to_string(p.sum()));  // 30

Pair<float64> fp = Pair<float64>(1.5, 2.5);
println(std::to_string(fp.sum()));  // 4.0
```

## Template Functions

```cpp
template<typename T>
T max_val(T a, T b) {
    if (a > b) return a;
    return b;
}

int32 m = max_val<int32>(10, 20);  // 20
```

## Template with Reference Parameters

```cpp
template<typename T>
void swap_vals(T& a, T& b) {
    T temp = a;
    a = b;
    b = temp;
}

int32 x = 10;
int32 y = 20;
swap_vals<int32>(x, y);  // x=20, y=10
```

## Nested Templates

Template functions can take template-typed args:

```cpp
template<typename T>
struct Box {
    T val;
    Box(T v) { val = v; }
    T get() { return val; }
}

template<typename T>
T unwrap(Box<T> b) {
    return b.get();
}

Box<int32> b = Box<int32>(42);
int32 v = unwrap<int32>(b);  // 42
```

Type args themselves can be template instantiations — `Pair<Pair<int64>>`, `Box<Box<Box<int64>>>`, etc. The closing `>>` parses without spacing in both type position and ctor-call position.

## Templated Base Classes

A class can inherit from a template instantiation:

```cpp
template<typename T> struct Box {
    T value;
    Box(T v) { value = v; }
    T get() { return value; }
}

struct IntBox : Box<int64> {
    IntBox(int64 v) : Box<int64>(v) {}
}

int64 main() {
    IntBox* b = new IntBox(42);
    int64 r = b->get();    // inherited from Box<int64>
    delete b;
    return r;
}
```

The init-list syntax `: Box<int64>(v)` invokes the instantiated base ctor. Override syntax in the derived class works as usual:

```cpp
struct Special : Box<int64> {
    Special(int64 v) : Box<int64>(v) {}
    int64 get() override { return value * 100; }
}
```

The `std` containers are themselves ordinary templates written in `.em` over this same surface — see [Std Library](/perception/enma-lang/addons/std-library.md) for what they offer. Heap accounting treats them like any user code: `heap_count()` reflects their allocations.

## Non-type parameters

A template parameter can be a value, not just a type.

```c
template<typename T, int64 N>
struct Buffer {
    T data[N];
    int64 size() { return N; }
}

Buffer<int64, 8> b;
```

## Specialization

Full specialization replaces the template for one exact argument list; partial specialization matches a shape.

```c
template<typename T> struct Traits { int64 tag() { return 0; } }

template<> struct Traits<int64> { int64 tag() { return 1; } }   // full
template<typename T> struct Traits<T*> { int64 tag() { return 2; } }  // partial
```

Value patterns work too — `template<typename T> struct C<T, 0>`.

## Variadic packs

`typename... Ts` declares a pack. `sizeof...(Ts)` is its length; a pack expands with `...`, and fold expressions collapse one into a single operation.

```c
template<typename... Ts>
int64 count(Ts... args) { return sizeof...(Ts); }

template<typename... Ts>
int64 total(Ts... args) { return (args + ... + 0); }    // fold
```

Classes take packs as fields (`Ts... name;`); functions expand recursively and accept zero-element packs.

## Alias and template-template parameters

```c
template<typename T> using Vec = std::vector<T>;

template<template<typename> class C>
struct Holder { C<int64> items; }
```

## CTAD and deduction guides

Class template arguments deduce from the constructor call, so `Box b(5)` gives `Box<int64>`. Where deduction needs steering, write an explicit guide:

```c
template<typename T> struct Box { T v; Box(T x) { v = x; } }
Box(T) -> Box<T>;

Box b(5);          // Box<int64>
```

A guide may carry its own `template<…>` prefix.

## if constexpr in templates

`if constexpr` discards the untaken branch, so it need not compile for the current instantiation. See [Compile-Time Evaluation](/perception/enma-lang/language-guide/compile-time.md#if-constexpr).

## Member templates

A template member is extracted and instantiated per use, and constructors may be templates.

## Dependent names

A template-id is a type wherever a type is expected, including to the left of `::`. `typename` marks a dependent qualified name as a type; `template` disambiguates a dependent member template.

```c
typename X<T>::type v;          // member type of an instantiation
int64 n = X<T>::value;          // member constant
p->template get<T>();           // dependent member template
```

## SFINAE

When substituting deduced arguments into a candidate's declaration produces an invalid type or expression, that candidate is removed from the overload set rather than failing the program — so trait-style dispatch on a return type, a parameter type, or a default template argument selects the viable overload.

A failure inside a function's **body** is a hard error, not a substitution failure, exactly as in C++.

## Constraints

`concept` definitions and `requires` clauses constrain a template. A requirement a type does not satisfy removes the candidate, and between two viable candidates the more constrained one wins. A `requires`-expression tests the validity of the expressions and type requirements it names.

```c
template<typename T> concept Addable = requires(T a, T b) { a + b; };

template<Addable T> T sum(T a, T b) { return a + b; }
```

## Deduction does not peel

Deduction does **not** unwrap `vector<T>&` to its element type. Container algorithms parameterize on the container, or take explicit `<T>`.

## RAII smart pointers

Templates, move semantics and deterministic destructors compose into C++-style smart pointers written in script. A move-only owning pointer:

```c
template<typename T>
struct unique_ptr {
    T* p;
    unique_ptr(T* raw) { p = raw; }
    unique_ptr(const unique_ptr<T>&) = delete;                 // non-copyable
    unique_ptr(unique_ptr<T>&& o) { p = o.p; o.p = null; }     // movable
    ~unique_ptr() { if (p != null) { delete p; } }
    T* get() { return p; }
}

unique_ptr<Node> a = unique_ptr<Node>(new Node(7));
unique_ptr<Node> b = move(a);     // ownership transfers; a is emptied
int64 v = b.get()->val;           // 7
// b's `delete` runs at scope exit — no leak, no double-free
```

A reference-counted `shared_ptr<T>` follows the same shape with a shared count the copy constructor increments and the destructor decrements, freeing the object at zero.
