EinfĂĽhrung in die Template-Spezialisierung
Templates definieren das Verhalten von Familien von Klassen oder Funktionen. Oft ist es erforderlich, spezielle Typen oder Nicht-Typen besonders zu behandeln. Um diesen Anwendungsfall zu erfĂĽllen, kannst du Templates spezialisieren.
- Rainer Grimm
Templates definieren das Verhalten von Familien von Klassen oder Funktionen. Oft ist es erforderlich, spezielle Typen oder Nicht-Typen besonders zu behandeln. Um diesen Anwendungsfall zu erfĂĽllen, kannst du Templates spezialisieren.
Zunächst möchte ich die allgemeine Idee hinter der Template-Spezialisierung beleuchten. Im nächsten Artikel konzentriere ich mich auf die Details.
Template-Spezialisierung
Templates definieren das Verhalten von Familien von Klassen und Funktionen. Oft ist es erforderlich, spezielle Typen oder Nicht-Typen besonders zu behandeln. Dazu kannst du Templates vollständig spezialisieren.
Klassen-Templates lassen sich auch teilweise spezialisieren. Das allgemeine oder primäre Template kann mit teilweise oder vollständig spezialisierten Templates koexistieren. Die Memberfunktionen und Attribute einer Spezialisierung müssen nicht identisch mit denen des primären Templates sein. Der Compiler bevorzugt vollständig spezialisierte gegenüber teilweise spezialisierten Templates, und teilweise spezialisierte Templates gegenüber primären Templates.
Das folgende Beispiel soll meine Worte verdeutlichen:
template <typename T, int Line, int Column> // (1)
class Matrix;
template <typename T> // (2)
class Matrix<T, 3, 3>{};
template <> // (3)
class Matrix<int, 3, 3>{};
- Primäre Templates
Zeile 1 beschreibt das primäre oder allgemeine Template. Das primäre Template muss vor den teilweise oder vollständig spezialisierten Templates deklariert werden. Wird das primäre Template nicht benötigt, ist eine Deklaration wie in Zeile 1 in Ordnung.
- Partielle Spezialisierung
In Zeile 2 folgt die partielle Spezialisierung. Nur Klassen-Templates unterstĂĽtzen partielle Spezialisierung. Eine partielle Spezialisierung hat Template-Parameter und explizit angegebene Template-Argumente. Im konkreten Fall der Klasse Matrix<T, 3, 3>
ist T
der Template-Parameter und die Zahlen sind die Template-Argumente.
- Vollständige Spezialisierung
Zeile 3 zeigt eine vollständige Spezialisierung. Vollständig bedeutet, dass alle Template-Argumente angegeben sind und die Template-Parameterliste leer ist: template <>
in Zeile 3.
Partielle versus vollständige Spezialisierung
Um die partielle und vollständige Spezialisierung besser zu verstehen, möchte ich eine visuelle Erklärung präsentieren. Du weißt vielleicht, dass ich Mathematik studiert habe und viele lineare Gleichungssysteme zu lösen hatte.
Denke an einen n-dimensionalen Raum von Template-Parametern. Eine partielle Spezialisierung ist ein Unterraum im n-dimensionalen Raum, und eine vollständige Spezialisierung ist ein Punkt im n-dimensionalen Raum.
Nun wende ich meine visuelle Erklärung auf das Klassen-Template Matrix
und ihre partielle und vollständige Spezialisierung an. In dem primären Template (Zeile 1) kannst du einen Typ als Template-Parameter und zwei int-Werte als Nicht-Typ-Template-Parameter wählen. Bei der partiellen Spezialisierung in Zeile 2 lässt sich nur der Typ auswählen. Das bedeutet, dass der 3-dimensionale Raum auf eine Linie reduziert wird. Die partielle Spezialisierung des primären Templates Matrix
ist somit ein Unterraum des 3-dimensionalen Raumes. Die volle Spezialisierung (Zeile 3) steht fĂĽr einen Punkt im 3-dimensionalen Raum.
Was passiert, wenn du das Template verwendest?
Verwendung der primären, partiellen und vollständigen Spezialisierung
Zur Erinnerung: Die folgenden Spezialisierungen der Klasse Matrix sind gegeben:
template <typename T, int Line, int Column> // (1)
class Matrix;
template <typename T> // (2)
class Matrix<T, 3, 3>{};
template <> // (3)
class Matrix<int, 3, 3>{};
Die Frage ist: Was passiert, wenn du Matrix fĂĽr verschiedene Template-Argumente instanziierst? Das folgende Beispiel zeigt drei Instanziierungen und deren Umsetzung durch den Compiler:
Matrix<int, 3, 3> m1; // class Matrix<int, 3, 3>
Matrix<double, 3, 3> m2; // class Matrix<T, 3, 3>
Matrix<std::string, 4, 3> m3; // class Matrix<T, Line, Column> => ERROR
m1
verwendet die vollständige Spezialisierung, m2
die partielle Spezialisierung und m3
das primäre Template. Da die Definition fehlt, verursacht die Verwendung von m3
einen Fehler.
Um diesen Prozess zu verstehen, musst du ein paar Regeln im Hinterkopf behalten. Die folgenden Regeln gelten insbesondere fĂĽr die partielle Spezialisierung von Klassen-Templates:
- Abhängigkeiten zwischen dem Template-Parameter und den Template-Argumenten
- Die Anzahl und Reihenfolge der explizit angegebenen Template-Argumente (
<T, 3, 3>
) muss mit der Anzahl und Reihenfolge der Template-Parameterliste(<typename T, int Line, int Column>
) des primären Templates übereinstimmen. - Wenn du Standardwerte für Template-Parameter verwendest, brauchst du die Template-Argumente nicht anzugeben. Nur das primäre Template akzeptiert Defaultwerte für Template-Parameter.
- GĂĽltige partielle Spezialisierungen
- Der Compiler wählt eine partielle Spezialisierung, wenn die Argumente der Template-Instanziierung (
Matrix<double, 3, 3>
) eine Teilmenge der Template-Argumente der partiellen Spezialisierung(Matrix<T, 3, 3>
) sind.
- Verwendete Template-Spezialisierung
- Der Compiler findet nur eine Spezialisierung. Er verwendet diese Spezialisierung.
- Der Compiler findet mehr als eine Spezialisierung. Er verwendet die am meisten spezialisierte. Wenn dieser Prozess in mehr als einer Spezialisierung endet, wirft der Compiler einen Fehler.
- Der Compiler findet keine Spezialisierung. Er verwendet die primäre Spezialisierung.
Okay, eine Frage muss ich noch beantworten. Was bedeutet es, dass ein Template A ein spezialisierteres Template ist als ein spezialisiertes Template B. Meine informelle Definition lautet wie folgt:
Ein Template A ist spezialisierter als ein Template B:
- Das Template B kann alle Argumente akzeptieren, die Template A akzeptieren kann.
- Das Template B kann Argumente akzeptieren, die Template A nicht akzeptieren kann.
Wenn du es formaler haben willst, besuche cppreference.com/partial_specialization und lies den Unterabschnitt ĂĽber partial ordering.
Wie geht's weiter?
Dieser Artikel sollte dir die Grundlagen zur Template-Spezialisierung vermitteln, aber wie immer gibt es in C++ mehr Details dazu. Zum Beispiel verhält sich partielle oder vollständige Spezialisierung wie ein if
zur Compilezeit und vollständige Spezialisierung von Klassen- oder Funktions-Templates sind den normalen Klassen oder Funktionen sehr ähnlich.
C++ Seminare
Im nächsten halben Jahr biete ich die folgenden Seminare an. Falls es die Covid-19 Situation zulässt, werde ich die Seminare nach Rücksprache als Präsenzseminare durchführen.
- C++20: 10.08.2021 - 12.08.2021 (Termingarantie)
- Embedded Programmierung mit modernem C++: 21.09.2021 - 23.09.2021
- Clean Code: Best Practices fĂĽr modernes C++: 14.12.2021 - 16.12.2021