opDispatch & opApply

D erlaubt es, Operatoren wie +, - oder den Aufrufoperator () für Klassen und Strukturen zu überladen. Im Folgenden werden die beiden speziellen Operatorüberladungen opDispatch und opApply genauer beleuchtet.

opDispatch

opDispatch kann als Memberfunktionen eines struct- oder class-Typs definiert werden. Jede unbekannte Memberfunktionsaufruf für diesen Typ wird an opDispatch weitergeleitet, wobei sowohl Name als auch Parameter der unbekannten Funktion als string durchgereicht werden. Damit ist opDispatch eine alles auffangede Memberfunktion und erlaubt eine andere Ebene der Generischen Programmierung, und das komplett zur Kompilierzeit!

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("called ", name);
        mixin("content." ~ name)(vals);
    }
}
CallLogger!C l;
l.callA(1, 2);
l.callB("ABC");

opApply

Eine alternative Implementing eines foreach-Durchlaufs, verglichen mit der Definition einer benuterdefinierten Range, ist die Erstellung einer opApply-Memberfunktion. Das Iterieren mit foreach oder ähnlichem wird ein spezielles Delegate als Parameter aufrufen:

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) {
    ...
}

Der Compiler wandelt den foreach-Rumpf in ein spezielles Delegate um, dass an das Objekt übergeben wird. Sein einziger Parameter ist jeweils der aktuelle Wert der Iteration. Der magische int-Rückgabewert muss interpretiert werden und, falls dieser nicht 0 ist, die Iteration abgebrochen werden.

Weiterführende Quellen

rdmd playground.d