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.
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 [1] 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 [2]: 10.08.2021 - 12.08.2021 (Termingarantie)
- Embedded Programmierung mit modernem C++ [3]: 21.09.2021 - 23.09.2021
- Clean Code: Best Practices fĂŒr modernes C++ [4]: 14.12.2021 - 16.12.2021
( [5])
URL dieses Artikels:
https://www.heise.de/-6118187
Links in diesem Artikel:
[1] https://en.cppreference.com/w/cpp/language/partial_specialization
[2] https://www.modernescpp.de/index.php/c/2-c/32-c-20
[3] https://www.modernescpp.de/index.php/c/2-c/33-embedded-programmierung-mit-modernem-c20210421085111
[4] https://www.modernescpp.de/index.php/c/2-c/34-clean-code-best-practices-fuer-modernes-c
[5] mailto:rainer@grimm-jaud.de
Copyright © 2021 Heise Medien