Drucken

Typen mit Charakter

Das in C++ existierende und mächtige, generische Konzept der Programmierung mit templates (Schablonen) hat sowohl Vor- als auch Nachteile. Einerseits kann man mit Hilfe von templates Funktionen oder Klassen relativ unabhängig von den zu erwarteten Typen deklarieren und definieren, um diese anschließend für spezielle Typen anzuwenden.

Kombiniert man das nun noch mit Vererbung und der Operatorüberladung, so sind templates insbesondere für die Bibliotheks-Entwicklung von sehr großem Nutzen, wie u.a. das Beispiel der C++ Standard Template Library (STL) zeigt.

Das templates die Typen, auf die sie operieren sollen, nicht vorab kennen, ist unter gewissen Umständen auch ein Nachteil. Ein Problem ist beispielsweise, das die von einem template zur Verfügung gestellten Algorithmen für einen unbekannten Typ A vielleicht sehr gut passen und auch performant sein mögen, hingegen selbige für einen Typ B gänzlich ungeeignet sind. Hilfreich wäre also ein Idiom, welches einem template in Abhängigkeit vom für einen Templateparameter eingesetzten konkreten Typ gewisse Informationen bereitstellt, damit der Compiler entscheiden kann, wie damit umzugehen ist bzw. um einen Compilerfehler zu erzeugen, wenn der eingesetzte Typ sogar gänzlich ungeeignet für das template ist. An dieser Stelle kommen die traits ins Spiel...

“Think of a trait as a small object whose main purpose is to carry information used by another object or algorithm to determine ‘policy’ or ‘implementation details’.” - Bjarne Stroustrup

Type traits (traits = dt.: Charakterzüge, Wesenszüge, Merkmale) sind quasi Meta-Informationen über Typen. Es handelt sich um eine Technik, um:

  • Informationen und Eigenschaften zu Typen bereit zustellen.
  • Operationen für bestimmte Typen zu abstrahieren.
  • Entscheidungen basierend auf Typen zur Compilezeit zu treffen.

Hier ein einfaches Beispiel für Traits:

#include <iostream>	// std::cout

// Basic template, always reflecting "value == false"
template< typename T >
struct is_int
{
	static const bool value = false;
};
 
// Now we specialise the base template to reflect those cases,
// where "value == true" (whenever the struct is specialised
// on integer types).
template<>
struct is_int<int>
{
	static const bool value = true;
};
 
template<>
struct is_int<unsigned int>
{
	static const bool value = true;
};
 
template<>
struct is_int<short>
{
	static const bool value = true;
};
 
template<>
struct is_int<unsigned short>
{
	static const bool value = true;
};
 
template<>
struct is_int<long>
{
	static const bool value = true;
};
 
template<>
struct is_int<unsigned long>
{
	static const bool value = true;
};

// The do_something template function, selecting the algorithm to
// apply to a value of type T depending on the type during
// compile-time
template <typename T>
void do_something(T param)
{
	if (is_int<T>::value)
	{
		std::cout << "Specialized algorithm for integer types." << std::endl;
	} else {
		std::cout << "Algorithm for non-integer types." << std::endl;
	}
}

Das Basis Traits-Template is_int enthält eine boolsche Konstante value, diese ist per default false. Anschließend folgen eine Reihe von Spezialisierungen dieses Templates für diverse Integer-Typen; in diesen Fällen wird die Konstante value auf true gesetzt. Die Template-Funktion do_something benutzt nun is_int, um eine Fallentscheidung durchzuführen: ist der Template-Parameter T ein Integer-Typ, so ist is_int::value true, ansonsten false.

Folgendes, kleines Test-Programm...

int main(int argc, char *argv[])
{
	int i = 0;
	double d = 0.0;

	do_something(i);
	do_something(d);

	return 0;
}

...erzeugt auf der Konsole folgende Ausgaben:

D:\Stephan\Development\Visual Studio 2008\Projects\Traits\Debug>traits
Specialized algorithm for integer types.
Algorithm for non-integer types.

In der STL werden Traits sehr häufig eingesetzt, ein Beispiel sind die Iterator-Traits (siehe http://www.sgi.com/tech/stl/iterator_traits.html).

Amazon Ads...

Hosted by...

Publicons

Google Ads...

Creative Commons License

Dieses Werk bzw. dieser Inhalt steht unter einer Creative Commons Namensnennung-Nicht-kommerziell-Weitergabe unter gleichen Bedingungen 3.0 Deutschland Lizenz.

Fork me on GitHub