Шаблоны типов

В Ü есть возможность создавать абстрактные типы, параметрезуемые другими типами или значениями. Такие типы называются шаблонами.

Шаблоны структур и классов

Для объявления шаблона структуры изи класса надо использовать ключевое слово template с перечислением через запятую списка параметров в <//> скобках. Параметры могут быть двух видов: тип и значение. Для указания параметра-типа перед его именем надо указать ключевое слово type. Для указания параметра-значения перед его именем следует указать имя типа.

template</ type T />
struct Box{ T t; }

template</ type T, size_type s />
struct Arr{ [ T, s ] arr; }

Для использования шаблона типа его надо инстанцировать. Для этого надо обратиться к шаблону, передав ему его аргументы:

template</ type T />
struct Box{ T t; }

template</ type T, size_type s />
struct Arr{ [ T, s ] arr; }

fn Foo()
{
    var Box</i32/> b_i{ .t= 0 };
    var Box</f32/> b_f{ .t= 0.0f };
    var Arr</ bool, 3s /> a{ .arr[ false, true, false ] };
}

Специализация и перегрузка шаблонов типов

В примерах выше использована короткая форма записи шаблонов структур и классов. Кроме этого существует полная форма записи шаблонов. В ней после имени структуры/класса указываются параметры, как они должны передаваться в шаблон - параметры сигнатуры. В параметрах сигнатуры можно указывать сложные имена типов - массивы, кортежи, функции, другие шаблоны. Также в полной форме записи можно указать параметры по умолчанию.

template</ type T />
struct TypeExtractor</ [ T, 4s ] />
{
    type ElementType= T;
}

// При обращении к шаблонной структуре указываем тип-массив, т. к. этот шаблон этого требует.
type E= TypeExtractor</ [ f32, 4s ] />::ElementType;

fn Foo() : E
{
    return 3.14f;
}
// Шаблон с параметром по умолчанию.
template</ type T, type U />
struct S</ T, U= i32 />
{
    T t;
    U u;
}

fn Foo()
{
    var S</ f32 /> s0{ .t= 0.0f, .u= 0 }; // Второй параметр не указан, будет выбран "i32" по умолчанию.
    var S</ i32, bool /> s1{ .t= 5, .u= false }; // Второй параметр указан.
}

Разрешено объявлять несколько шаблонов с одним именем, но с разными параметрами, такими, чтобы параметры были разными. В случае, когда к указанным параметрам подходят несколько шаблонов, выбирается более специализированный шаблон.

Правила специализации следующие: конкретный тип лучше типа массива, кортежа, шаблона. Тип массива, кортежа, шаблона лучше, чем параметр шаблона.

template</ type T, size_type S />
struct S</ [ T, S ] />
{
    auto x= 1;
}

template</ type T />
struct S</ T />
{
    auto x= 2;
}

static_assert( S</ i32 />::x == 2 );
static_assert( S</ [ f32, 64s ] />::x == 1 );

Шаблонные аргументы-значения

Как уже было упомянуто ранее, аргументами шаблонов могут быть не только типы, но и constexpr значения. Допустимы значения типа bool, целочисленных типов, символьных типов, byte-типов, перечислений. Кроме того дозволены массивы и кортежи, составленные из вышеописанных типов.

enum E { A, B, C }
type ArgType= tup[ [ i32, 2 ], char8, bool, E ];

// Шаблон структуры с композитным параметром.
template</ ArgType arg /> struct S {}

var ArgType constexpr my_arg[ [ 7, -5 ], "y"c8, true, E::B ];

// Параметрезуем шаблон композитным значением.
type MyS= S</ my_arg />;

Шаблонные аргументы-шаблоны типов

Шаблоны типов могут также выступать в качестве аргументов шаблонов. При этом в качестве аргумента можно использовать только неперегруженные шаблоны типов.

template</type T/> struct Box{ T val; }

template</ type template Container /> // У этого шаблона структуры есть единственный параметр - шаблон типа.
struct ContainedIntPair
{
    // Используем шаблон типа - параметр этого шаблона.
    Container</i32/> first;
    Container</i32/> second;
}

type BoxedIntPair= ContainedIntPair</ Box />; // Передаём в качестве аргумента шаблона шаблон типа Box.

var BoxedIntPair pair{ .first{ .val= 66 }, .second{ .val= 77 } };

Шаблоны псевдонимов типов

Существуют также шаблоны псевдонимов типов. Работа с ними схожа с шаблонами структур и классов.

template</ type T />
struct Box{ T t; }

template</ type T /> type BoxAlias= Box</ T />; // Псевдоним для шаблонной структуры
template</ type T /> type MyVec3= [ T, 3 ]; // Шаблон для массива