zurück zum Artikel

EinfĂŒhrung in die Template-Spezialisierung

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.

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.

Template-Spezialisierung

ZunÀchst möchte ich die allgemeine Idee hinter der Template-Spezialisierung beleuchten. Im nÀchsten Artikel konzentriere ich mich auf die Details.

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>{};

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.

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.

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.

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?

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:

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:

Wenn du es formaler haben willst, besuche cppreference.com/partial_specialization [1] und lies den Unterabschnitt ĂŒber partial ordering.

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.

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.

( [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