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

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

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

Для объявления шаблона структуры изи класса надо использовать ключевое слово 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 );

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

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

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

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