Template Metaprogramming
Einfach alle Objekte mit anderen Grenzen für eine Zuweisung abweisen ist nicht ganz das richtige. Eigentlich möchten wir abhängig von den Grenzen des anderen Objektes lieber eine Prüfung durchführen oder eben auch nicht. Template Metaprogramming macht genau das möglich.
Video
Code
|
|
Erklärung
Unser RangeInt
-Template vom letzten Mal ist etwas über’s Ziel hinaus geschossen: wir können nun nur noch Objekte gleicher
Typen aufeinander zuweisen. Eigentlich könnten wir die Regel etwas lockerer gestalten: Sind die Grenzen der Quelle enger
oder gleich den Grenzen des Ziels, dann können wir uns die Bereichsprüfung sparen. Sonst müssen wir sie durchführen. Das
Problem ist hier: wir müssen diese Prüfung bei der Übersetzung durchführen.
Die Technik, die uns das erlaubt, nennt sich Template Metaprogramming. So richtig Absicht war das nicht, dass man die in C++
eingebaut hat. Sie folgt vielmehr aus den Regeln, nach denen Templates zur Instanziierung ausgewählt werden und wie
Compile-Time-Konstanten funktionieren. In unserem Fall steckt die Hauptarbeit im Funktionstemplate check
und seinen beiden
Spezialisierungen in Zeile 6 und 14. Dieses Template hat einen einzelnen bool
-Parameter. Der ist unsere Bedingung: ist er
true
(Spezialisierung in Zeile 6), dann müssen wir die Prüfung durchführen, ist er false
(Spezialisierung in Zeile 14),
dann nicht. Im Grunde genommen zeigt dieser Parameter also die Überprüfung der Grenzen durch den Compiler an.
Wie werden diese Grenzen nun überprüft? Dazu müssen wir uns zum Beispiel den Copy-Assignment-Operator anschauen. Dort sehen
wir in Zeile 39 eine Instanziierung des check
-Templates mit einem komplexen Ausdruck in der Parameterliste. Sämtliche
Variablen in diesem Ausdruck sind Compile-Time-Konstanten (die beiden Grenzen der eigenen Templateinstanz, wie auch die
Grenzen der anderen Instanz). Damit muss der Compiler diesen Ausdruck auswerten können (sagt der Standard) und auf einen
Wert zusammenführen (true
oder false
in unserem Falle). Dieser Wert wird dann für die Instanziierung des Templates
genutzt, womit wir die passende Variante auswählen. Da unsere beiden Template-Funktionen inline
sind, wird ihr Inhalt
direkt an dieser Stelle eingesetzt (statt einen Funktionsaufruf zu generieren). Wenn unser Check also nicht durchgeführt
werden muss (die false
-Spezialisierung), dann wird auch tatsächlich überhaupt kein Code an dieser Stelle ausgeführt.
Möglich ist die Instanziierung des passenden check
-Templates, weil der Copy-Assignment-Operator seinerseits auch ein
Template ist, welches seine beiden Template-Parameter aus dem übergebenen Objekt ableitet. Jedesmal, wenn wir so eine
Zuweisung brauchen, wird also der passende Copy-Assignment-Operator instanziiert, der wiederum das passende check
-Template
instanziiert, welches dann eben prüft oder nicht.
Was wir hier mittels Template Metaprogramming implementiert haben ist eine zur Compile-Zeit geprüfte if
-Anweisung (oder
ein switch
mit nur zwei Pfaden). Insgesamt geht da noch deutlich Komplexeres, aber dazu in einem anderen Video mehr.