Перегрузка операторов

Для типов структур и классов возможно перегрузить ряд операторов и операций. Перегруженный оператор это просто функция внутри класса и структуры, имеющая специальное имя и выполняющая ряд требований. У всех перегруженных операторов и операций тип одного из аргументов должен быть той структуры или того класса, в которой объявлены операция или оператор.

Объявляется перегруженный оператор с использованием ключевого слова op и имени оператора после него.

struct Int
{
    i32 x;

    op+( Int& l, Int& r ) : Int // Перегруженный бинарный оператор
    {
        var Int i{ .x= l.x + r.x };
        return i;
    }

    op-( Int& a ) : Int // Перегруженный префиксный унарный оператор
    {
        var Int b{ .x= -a.x };
        return b;
    }

    op++( mut this ) // Перегруженная унарная операция
    {
        ++x;
    }

    op[]( this, i32 y ) : i32 // Перегруженный постфиксный оператор
    {
        return x * y;
    }
}

fn Foo()
{
    var Int mut a{ .x= 42 }, b{ .x= 666 };
    ++a;
    auto ab= a + b;
    auto minus_b= -b;
    var i32 r= a[5];
}

Перегружаемые операторы и операции:

Оператор тип Число аргументов Возвращаемый результат
- префиксный оператор 1 любой
! префиксный оператор 1 любой
~ префиксный оператор 1 любой
+ бинарный оператор 2 любой
- бинарный оператор 2 любой
* бинарный оператор 2 любой
/ бинарный оператор 2 любой
% бинарный оператор 2 любой
& бинарный оператор 2 любой
| бинарный оператор 2 любой
^ бинарный оператор 2 любой
>> бинарный оператор 2 любой
<< бинарный оператор 2 любой
== бинарный оператор 2 bool
<=> бинарный оператор 2 i32
[] постфиксный оператор 2 любой
() постфиксный оператор 1 и более любой
++ унарная операция 1 void
-- унарная операция 1 void
= бинарная операция 2 void
+= бинарная операция 2 void
-= бинарная операция 2 void
*= бинарная операция 2 void
/= бинарная операция 2 void
%= бинарная операция 2 void
&= бинарная операция 2 void
|= бинарная операция 2 void
^= бинарная операция 2 void
<<= бинарная операция 2 void
>>= бинарная операция 2 void

Ряд перегруженных операторов вызываются особым образом.

Для == и != вызывается перегруженный оператор ==. Не существует отдельной перегрузки оператора !=. Для получения результата != результат вызова == инвертируется.

Для операторов упорядочивающего сравнения (<, <=, >, >=) вызывается перегруженный оператор <=>. Результат его вызова сравнивается с нулём для получения конечного результата. Перегруженному оператору <=> не обязательно возвращать строго -1 или +1 для индикации отношения больше/меньше, важен лишь знак результата.

Постфиксные операторы

Особое место занимают постфиксные операторы. У всех них есть требование, чтобы тип первого аргумента был тот же, что у типа структуры или класса, где объявлен этот оператор.

Оператор индексирования [] позволяет обращаться по индексу к структуре или классу, как будто это массив. При этом тип индекса может быть любым. Это позволяет, например, организовать ассоциативные контейнеры с доступом по ключу с использованием данного оператора.

Оператор вызова () позволяет обращаться с структурой или классом подобно функции. Это позволяет, например, реализовывать функциональные объекты.