Шаблоны функций

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

Для объявления шаблонной функции надо объявить её с использованием ключевого слова template и перечислить список параметров, так же, как в шаблонах типов. Инстанцировать шаблонную функцию можно, вызвав её.

template</ type T />
fn min( T &imut a, T &imut b ) : T &imut
{
    if( a < b ) { return a; }
    return b;
}

template</ type T, size_type S />
fn FillWithZeros( [ T, S ] &mut arr )
{
    foreach( &mut el : arr )
    {
        el= T(0);
    }
}

fn Foo()
{
    var i32 x= min( 55, 9 );
    var [ f64, 4 ] mut arr[ 1.0, 1.0, 1.0, 1.0 ];
    FillWithZeros( arr );
}

Параметры шаблона выводятся из переданных аргументов функции. Если вывести их невозможно, нужно указать явно все параметры или только сколько-то первых из них.

template</ type T />
fn GetPi() : T
{
    return T(3.1415926535);
}

auto constexpr pi_f= GetPi</f32/>();
auto constexpr pi_d= GetPi</f64/>();

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

Можно объявить несколько шаблонных и нешаблонных функций в одном пространстве имён с одним и тем же именем. При вызове функции будет инстанцироваться наиболее специализированная шаблонная функция. Правила специализации такие же, как в специализации шаблонов типов.

template</ type T />
fn GetSequenceSize( T& t ) : size_type // Функция для произвольных типов
{
    return 0s;
}

template</ type T, size_type S />
fn GetSequenceSize( [T, S] &arr ) : size_type // Специализация для массивов
{
    return S;
}

fn constexpr GetSequenceSize( tup[] &t ) : size_type // Нешаблонная функция, специализированная для пустых кортежей. Считается более специализированной, чем предыдущая шаблонная функция.
{
    return 0s;
}

template</ type T />
fn GetSequenceSize( tup[T] &t ) : size_type // Специализация для кортежей с размером 1
{
    return 1s;
}

template</ type T, type U />
fn GetSequenceSize( tup[T, U] &t ) : size_type // Специализация для кортежей с размером 2
{
    return 2s;
}

template</ type T, type U, type V />
fn GetSequenceSize( tup[T, U, V] &t ) : size_type // Специализация для кортежей с размером 3
{
     return 3s;
}

var i32 constexpr i= 0;
static_assert( GetSequenceSize(i) == 0s );

var [ bool, 16 ] constexpr arr= zero_init;
static_assert( GetSequenceSize(arr) == 16s );

var tup[] constexpr t0= zero_init;
static_assert( GetSequenceSize(t0) == 0s );

var tup[ f32 ] constexpr t1= zero_init;
static_assert( GetSequenceSize(t1) == 1s );

var tup[ bool, i32 ] constexpr t2= zero_init;
static_assert( GetSequenceSize(t2) == 2s );

var tup[ f32, u64, i32 ] constexpr t3= zero_init;
static_assert( GetSequenceSize(t3) == 3s );

constexpr для шаблонных функций

Так же, как и обычную функцию, шаблонную функцию можно объявить как constexpr. В таком случае будет проверяться соблюдение constexpr требований к каждому инстанцированию функции. Если же не объявлять шаблонную функцию constexpr, каждое её инстанцирование будет автоматически помечаться как constexpr, если соответствующие требования соблюдены, и не будет помечаться, если не соблюдены.