D позволяет переопределять операторы, такие как
+, - или оператор вызова () для
классов и структур.
Взглянем поближе на переопределение специальных операторов
opDispatch и opApply.
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");
Альтернативный способ реализации итерирования посредством
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,
прекратить цикл.