Twitter und Facebook-Anbindung
X
Tweet Follow @twitterapi
!!! Anbindung an twitter und facebook öffnen !!!

Wenn Ihnen mein Online-Buch gefällt,
dann bedanken Sie sich doch mit einer kleinen Spende...

24.5.4 Spezialisierung von Templates

24.5.4 Spezialisierung von Templates

Das eben gezeigte Beispiel hatte unter anderem eine große Schwäche. Der implementierte Container konnte zwar Daten halten, aber nicht sinnvoll initialisieren. Es fehlt also im Standardkonstruktor eine Schleife, in welcher jedem Element ein sinnvoller Startwert zugewiesen wird. Doch welcher Wert ist Sinnvoll? Sicher könnte man im Falle von Integern und Zeigern den Wert null zuweisen, aber schon bei Floats wird es kritisch, denn man müsste "0.0f" angeben. Noch verzwickter wird es, wenn der Container irgendwelche Objekte halten soll. Was können wir also tun?

Die Antwort auf diese Frage ist die Spezialisierung von Templates. Die Grundidee ist, dass man einen allgemein gültigen Fall definiert und dann noch weitere, welche auf spezielle Datentypen eingeht. Jetzt müssten Sie eigentlich mit der Stirn runzeln, denn der Vorteil von Templates ist doch, dass man nur einmal Code schreiben muss und er dann universell einsetzbar ist. Eine erneute Implementierung ist doch genau das Gegenteil. Stellen wir diesen Aspekt aber mal ganz kurz in den Hintergrund und schauen wir uns zunächst das Prinzip an.

Im folgenden Beispiel greife ich das Beispiel von eben auf, wobei ich in der Klassendefinition die Implementierung des Standardkonstruktors entferne (es wird nur noch der Prototyp dastehen) und unterhalb der Klassendefinition mehrfach spezialisiert implementiere. Die Klassendefinition selbst spare ich mir an dieser Stelle.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
					
// Standardkonstruktor ////////////////////////////////////////////////////////
template<typename TDataType, unsigned int TSize>
CContainer<TDataType, TSize>::CContainer() {
	printf("Allgemeines Template\n");
	// keine Initialisierung
} // CContainer ///////////////////////////////////////////////////////////////



template<>
CContainer<float>::CContainer() {
	printf("Spezialisiertes Template 1\n");
	for (unsigned int iCount = 0; iCount < GetSize(); ++iCount) {
		m_aItems[iCount] = 0.0f;
	} // end of for
} // CContainer ///////////////////////////////////////////////////////////////



template<>
CContainer<float, 32>::CContainer() {
	printf("Spezialisiertes Template 2\n");
	for (unsigned int iCount = 0; iCount < 32; ++iCount) {
		m_aItems[iCount] = 0.0f;
	} // end of for
} // CContainer ///////////////////////////////////////////////////////////////



template<>
CContainer<int>::CContainer() {
	printf("Spezialisiertes Template 3\n");
	for (unsigned int iCount = 0; iCount < GetSize(); ++iCount) {
		m_aItems[iCount] = 0;
	} // end of for
} // CContainer ///////////////////////////////////////////////////////////////



// Achtung, jede Templatedefinition mit unterschiedlichen Templateparametern
// bedeutet auch ein unterschiedlicher Datentyp (nicht polymorph)! 
typedef CContainer<float>	CsmallFloatContainer;
typedef CContainer<float, 32>	CbigFloatContainer;
typedef CContainer<int>		CsmallIntContainer;
typedef CContainer<double>	CDoubleContainer;

// ...

CSmallFloatContainer		oContainer1;
CBigFloatContainer		oContainer2;
CSmallIntContainer		oContainer3;
CPoinerContainer		oContainer4;
					

Ausgabe

Spezialisiertes Template 1
Spezialisiertes Template 2
Spezialisiertes Template 3
Allgemeines Template
		

Wie Sie sehen können, habe ich den Standardkonstruktor jetzt mehrfach definiert. Ich überlade ihn aber nicht, sondern ich definiere ihn für verschiedene Szenarien. Zu Beginn, also in den Zeilen 2 bis 6, muss immer die allgemeine Form dastehen, in welcher der allgemeine Fall abgehandelt wird. Da man allgemein nicht sagen kann, wie ein Wert initialisiert werden muss, passiert hier nicht wirklich etwas.

Jetzt fängt es an spannend zu werden. Die nachfolgenden Implementierungen sehen jetzt anders aus. Schauen wir uns zuerst Zeile 10 an. Hier wird wieder das Template angegeben, zu welchem die Methode gehört, aber seltsamerweise habe ich jetzt keine Templateparameter angegeben. Immer dann, wenn Sie so etwas sehen, handelt es sich um eine Spezialisierung eines Templates. Warum muss ich hier keinen Templatetyp angeben? Die Antwort folgt in Zeile 11. Hier folgt jetzt der Methodenkopf und hier wird in den spitzen Klammern ein Primitivtyp angegeben. Somit habe ich aus dem allgemeinen Fall "TDataType" den speziellen Fall "float" definiert. Auch in den Zeilen 12 bis 16 taucht der Type "TDataType" nicht mehr auf. Sicher fragen Sie sich jetzt, was mit "TSize" geworden ist. Da es sich um keinen Templatetyp handelt (viel mehr um eine Art Konstante), braucht man hier nichts anzugeben. Allerdings benötigt ich die Größe dann doch, wenn ich in der for Schleife die Werte initialisieren will. Da "TSize" in diesem Kontext nicht definiert ist, kann ich es nicht verwenden. Somit braucht die Klasse also einen Getter, um genau diesen Wert zu liefern.

Schauen wir uns nun Zeile 20 bis 26 an. Auf den ersten Blick passiert hier das Gleiche, aber bei näherem Betrachten entdeckt man in Zeile 21 einen Unterschied. Dieses mal spezialisiere ich nicht nur den Templatetypen, sondern auch den Primitivtypen. In dem Moment, in welchem ich so etwas mache, kann ich diesen konstanten Wert auch innerhalb der Methode benutzen und somit benötigt ich nicht mehr die Methode "GetSize".

In den Zeilen 30 bis 36 sehen Sie eine Spezialisierung für den Templatetypen Integer. Da ich hier wieder keinen Primitivtypen angegeben habe, muss ich wieder auf den klasseninternen Getter zurückgreifen.

In den Zeilen 42 bis 45 sehen Sie erneute Typendefinitionen. Sie ähneln denen aus dem letzten Beispiel und sollen noch einmal verdeutlichen, dass es sich immer um andere Typen handelt, wenn man das Template mit anderen Parametern benutzt.

Abschließend sehen Sie dann, dass ich lediglich verschiedene Objekte erzeuge, wobei die unterschiedlichen Spezialisierungen genutzt werden. Anhand der Ausgabe sehen Sie, welche Spezialisierung genau benutzt wird. Nur für den Fall, dass keiner der Templateparameter den spezialisierten entspricht, wird die allgemeine Definition benutzt.

Zum Seitenanfang
Zum Inhaltsverzeichnis

© Copyright by Thomas Weiß, 2009 - 2012