Menu

opDispatch и opApply

D позволяет переопределять операторы, такие как +, - или оператор вызова () для классов и структур. Взглянем поближе на переопределение специальных операторов opDispatch и opApply.

opDispatch

opDispatch можно определить как функцию-член для типов struct или class. Все неизвестные вызовы членов такого типа передаются в opDispatch, при этом имя неизвестного члена передаётся как параметр шаблона типа string. opDispatch - это перехватывающая всё функция-член, предоставляющая дополнительный уровень обобщённого программирования - полностью во время компиляции!

struct C {
    void callA(int i, int j) { ... }
    void callB(string s) { ... }
}
struct CallLogger(C) {
    C content;
    void opDispatch(string name, T...)
                                 (T vals) {
        writeln("вызов ", name);
        mixin("content." ~ name)(vals);
    }
}
CallLogger!C l;
l.callA(1, 2);
l.callB("ABC");

opApply

Альтернативный способ реализации итерирования посредством foreach без необходимости определять пользовательский диапазон - реализация функции-члена opApply. Итерирование такого типа при помощи foreach приводит к вызову opApply с параметром в виде специального делегата:

class Tree {
    Tree lhs;
    Tree rhs;
    int opApply(int delegate(Tree) dg) {
        if (lhs && lhs.opApply(dg))
            return 1;
        if (dg(this))
            return 1;
        if (rhs && rhs.opApply(dg))
            return 1;
        return 0;
    }
}
Tree tree = new Tree;
foreach(node; tree) {
    ...
}

Компилятор преобразует тело foreach в специальный делегат, который передаёт объекту. Единственный его параметр - индекс текущей итерации. "Волшебное" возвращаемое значение типа int необходимо интерпретировать и в случае, если это не 0, прекратить цикл.

Подробнее

rdmd playground.d