Suchen

Programmierung zur Compilezeit

Seite: 2/3

Firma zum Thema

Die Type-Traits-Bibliothek

Die Type-Traits Bibliothek erlaubt es, Typabfragen, -vergleiche und –transformationen zur Compilezeit auszuführen. Sie ist eine Anwendung der Template Metaprogrammierung und verfolgt vor allem zwei Ziele: Korrektheit und Optimierung.

Korrektheit

Bildergalerie

Bildergalerie mit 12 Bildern

Die Type-Traits Bibliothek erlaubt es in Kombination mit dem static_assert Ausdruck, verbindliche Bedingungen an den Sourcecode zu stellen, die zur Compilezeit ausgewertet werden.

Der gcd-Algorithmus zur Berechnung des größten gemeinsamen Teilers zweier Ganzzahlen ist viel zu generisch. So lässt er sich zwar mit Fließkommazahlen, Strings und unterschiedlichen Datentypen wie int(100) und long int (10L) verwenden. Der Compiler quittiert dies aber mit einer sehr wortreichen Fehlermeldung in Bild 5 (vgl. Bildergalerie).

Durch die Type-Traits Bibliothek lassen sich die Bedingungen an den Algorithmus explizit stellen. Und das alles ohne zusätzliche Kosten für die Laufzeit des Programmes (vgl. Bild 6 in der Bildergalerie).

So prüft der neue gcd-Algorithmus, ob die beiden Template-Argumente T1 und T2 Ganzzahlen sind: std::is_integral<T1>::value. Als Rückgabetyp für den größten gemeinsamen Teiler gibt der gcd-Algorithmus den kleineren der beiden Typen zurück: std::conditional<(sizeof(T1)<sizeof(T2)),T1,T2>::type.

Optimierung

Code zu schreiben, der sich beim Übersetzen selbst optimiert, das erlaubt die Type-Traits Bibliothek. So enthält die Standard Template Library (STL) optimierte Versionen der bekannten Algorithmen std::copy, std::fill oder std::equal.

Die Idee ist recht einfach. Immer, wenn die Algorithmen auf Container agieren, deren Elemente hinreichend einfach sind, kommt ein optimierter Algorithmus zum Einsatz. Damit ist es möglich, die Elemente nicht elementweise zu kopieren (std::copy), zu füllen (std::fill) oder zu vergleichen (std::equal), sondern ganze Containerbereiche zu bearbeiten. Dafür kommen die C-Funktionen memmove, memset und memcpy zum Einsatz.

Ob die Containerelemente hinreichend einfach sind, entscheiden zur Compilezeit die Funktionen der Type-Traits Bibliothek (vgl. Bild 7 in der Bildergalerie).

Wird std::fill aufgerufen, verwendet der Compiler die Implementierungsfunktion fill_impl mit std::memset genau dann, wenn die Elemente des Containers einen vom Compiler automatisch erzeugten Kopierkonstruktor besitzen und ein Byte groß sind: is_trivially_copy_assignable<T>::value && (sizeof(T) == 1.

Der Performanzunterschied ist signifikant. So wird in dem Programm ein Array mit 100.000.000 Elementen gefüllt (vgl. Bild 8 in der Bildergalerie).

Während die Elemente des charArray1 mit der Zahl 1 initialisiert werden, die in der Regel 4 oder 8 Byte große ist, wird charArray2 mit einer char initialisiert: static_cast<char>(1) (vgl. Bild 9 in der Bildergalerie).

Die performante Version des Algorithmus ist um den Faktor 20 schneller.

(ID:44192399)