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.5 Type Traits

24.5.5 Type Traits

Wie ich mehrfach erwähnte, ist es eher unpraktisch, ein und die selbe Methode mehrfach zu definieren, nur um alle Datentypen abzudecken. Es stellt sich also die Frage, ob man dies nicht eleganter lösen kann. Hier kommen die s.g. Type Traits ins Spiel. Die Grundidee ist, dass man einen Mechanismus baut, mit welchem man später erkennt, um welchen Templatetypen es sich handelt und dann mit einer einfachen if Anweisung unterscheidet. So wird zwar die Implementierung der entsprechenden Methode größer, aber man braucht nur noch eine. Hier also mal ein vereinfachtes Beispiel für einen Type Trait.

 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
					
template<typename Ttype> struct STypeTrait {
	static const bool	IsPointer	= false;
	static const bool	IsInt		= false;
	static const bool	IsFloat		= false;
	static const bool	IsUnknown	= true;
};

template<typename Ttype> struct STypeTrait<TType*> {
	static const bool	IsPointer	= true;
	static const bool	IsInt		= false;
	static const bool	IsFloat		= false;
	static const bool	IsUnknown	= false;
};

template<> struct STypeTrait<int> {
	static const bool	IsPointer	= false;
	static const bool	IsInt		= true;
	static const bool	IsFloat		= false;
	static const bool	IsUnknown	= false;
};

template<> struct STypeTrait<float> {
	static const bool	IsPointer	= false;
	static const bool	IsInt		= false;
	static const bool	IsFloat		= true;
	static const bool	IsUnknown	= false;
};
					

Auch hier habe ich wieder ein allgemeines Template und Spezialisierungen des selben gebaut. Viel Logik wird hier nicht implementiert. Der einzige Zweck ist mir eine Mechanismus zu erzeugen, mit welchem ich Prüfen kann, von welchem Typ ein Templateparameter ist. Zudem ist es mir jetzt auch möglich, zwischen normalen Datentypen und Pointern zu unterscheiden. Dies ist ganz praktisch, wenn man später mal unterscheiden möchte, ob ein Objekt, oder ein Zeiger auf ein Objekt übergeben wurde, da man bei erstem üder den Punktoperator auf die Member zugreift und bei letzterem über den Pfeiloperator.

Ich werde jetzt das bisherige Beispiel wieder aufgreifen, aber so modifizieren, dass ich genau die eben erstellten Templatestrukturen dafür verwenden kann, um Typprüfungen vorzunehmen.

31
32
33
34
35
36
37
38
39
40
41
42
43
44
					
// Sehr einfacher Datencontainer //////////////////////////////////////////////
template<typename TDataType, unsigned int TSize> class CContainer {
	public:
		typedef TDataType			TType;
		typedef CContainer<TDataType, TSize>	TSelf;

		// Standardkonstruktor ////////////////////////////////////////////
		CContainer(); /////////////////////////////////////////////////////

		// ...

	private:
		TDataType m_aItems[TSize];
}; // CContainer //////////////////////////////////////////////////////////////
					

Die Klassendefinition ist wieder fast die Gleiche, nur dass ich die Defaulttypen für die Templateparameter entfernt habe. Interessant wird jetzt der modifizierte Standardkonstruktor.

48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
					
// Standardkonstruktor ////////////////////////////////////////////////////////
template<typename TDataType, unsigned int TSize>
CContainer<TDataType, TSize>::CContainer() {
	if (STypeTrait<TDataType>::IsUnknown) {
		printf("Nicht implementierter Typ\n");
		return;
	} else if (STypeTrait<TDataType>::IsPointer) {
		printf("Pointer\n");

		// Alles Initialisieren
		for (unsigned int iCount = 0; iCount < TSize; ++iCount) {
			m_aItems[iCount] = NULL;
		} // end of for
	} else if (STypeTrait<TDataType>::IsInt) {
		printf("Integer\n");

		// Alles Initialisieren
		for (unsigned int iCount = 0; iCount < TSize; ++iCount) {
			m_aItems[iCount] = 0;
		} // end of for
	} else if (STypeTrait<TDataType>::IsFloat) {
		printf("Float\n");

		// Alles Initialisieren
		for (unsigned int iCount = 0; iCount < TSize; ++iCount) {
			m_aItems[iCount] = static_cast<TDataType>(0);
		} // end of for
	} // end of if
} // CContainer ///////////////////////////////////////////////////////////////
					

Wie Sie sehen können, kann ich jetzt innerhalb einer Methode auf die verschiedenen Datentypen eingehen und so getrennte Initialisierungen vornehmen. Ganz so einfach ist es dann aber auch nicht, wie Sie in Zeile 73 sehen können. Es ist mir nicht möglich dem Float den Wert "0.0f" zuzuweisen, da sich der Compiler genau an dieser Stelle beschweren wird, wenn man dem Template ein Pointer übergibt. Der Wert null ist aber an dieser Stelle nicht schädlich und bringt nur eine Warnung, die Sie getrost ignorieren können.

Damit Sie sehen, dass der ganze Spaß auch funktioniert, hier noch der Teil für den Aufruf und die Verwendung der modifizierten Klasse.

80
81
82
83
84
85
86
87
88
					
typedef CContainer<double*, 16>	CPoinerContainer;
typedef CContainer<float, 16>	CFloatContainer;
typedef CContainer<int, 16>	CIntContainer;
typedef CContainer<char, 16>	CCharContainer;

CPoinerContainer	oContainer1;
CFloatContainer		oContainer2;
CIntContainer		oContainer3;
CCharContainer		oContainer4;
					

Ausgabe:

Pointer
Float
Integer
Nicht implementierter Typ
		

Wie Sie sehen können, funktioniert diese Lösung perfekt. Falls Sie sich mehr für dieses Thema und die daraus resultierenden Möglichkeiten informieren wollen, schauen Sie einfach im Internet nach. Dort finden Sie unzählige Artikel und Beispiele, sowie ganze Bibliotheken zu diesem Thema.

Abschließend möchte ich noch sagen, dass dies lediglich ein kleiner Vorgeschmack auf dessen ist, was mit Templates alles möglich ist und wie man Sie verwenden kann. Es gibt ganze Bücher zu diesem Thema und deswegen gehe ich nicht weiter darauf ein. Sie sollten lediglich das Grundkonzept verstanden haben, da es auch andere Sprachen gibt (z.B. Java), in welchem Templates möglich sind (wenn auch nicht in dem Umfang wie in C++).

Zum Seitenanfang
Zum Inhaltsverzeichnis

© Copyright by Thomas Weiß, 2009 - 2012