Шаблоны типов¶
В Ü есть возможность создавать абстрактные типы, параметрезуемые другими типами или значениями. Такие типы называются шаблонами.
Шаблоны структур и классов¶
Для объявления шаблона структуры изи класса надо использовать ключевое слово 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 ]; // Шаблон для массива