Typen haben unterschiedliche Eigenschaften, die sich die generische Programmierung zunutze macht. Dazu ist es notwendig, Typen auf Eigenschaften zu überprüfen oder ihre Eigenschaften zu ändern. Boost.TypeTraits ist die Bibliothek, die die dazu erforderlichen Hilfsmittel bietet.
Seit C++11 befindet sich ein Teil der Funktionen, die Boost.TypeTraits anbietet, in der Standardbibliothek. Sie können auf diese Funktionen über die Headerdatei type_traits
zugreifen. Boost.TypeTraits bietet jedoch bedeutend mehr Funktionen an als Sie in type_traits
vorfinden.
#include <boost/type_traits.hpp>
#include <iostream>
using namespace boost;
int main()
{
std::cout.setf(std::ios::boolalpha);
std::cout << is_integral<int>::value << '\n';
std::cout << is_floating_point<int>::value << '\n';
std::cout << is_arithmetic<int>::value << '\n';
std::cout << is_reference<int>::value << '\n';
}
Im Beispiel 48.1 kommen verschiedene Funktionen zum Einsatz, mit denen Typ-Kategorien abgefragt werden können. So wird mit boost::is_integral
überprüft, ob ein Typ integral ist – ob er also Ganzzahlen speichern kann. Mit boost::is_floating_point
wird überprüft, ob ein Typ Kommazahlen speichern kann. boost::is_arithmetic
wird verwendet, um zu überprüfen, ob ein Typ arithmetische Operationen unterstützt. Und boost::is_reference
kann verwendet werden, um herauszufinden, ob ein Typ eine Referenz ist.
Beachten Sie, dass sich boost::is_integral
und boost::is_floating_point
gegenseitig ausschließen. Ein Typ speichert entweder Ganz- oder Kommazahlen. boost::is_arithmetic
und boost::is_reference
sind hingegen kategorieübergreifend. So werden zum Beispiel arithmetische Operationen sowohl von Ganz- als auch Kommazahlen unterstützt.
Alle Funktionen von Boost.TypeTraits bieten mit value ein Ergebnis an, das entweder true
oder false
ist. Wenn Sie Beispiel 48.1 ausführen, wird für is_integral<int>
und is_arithmetic<int>
true
und für is_floating_point<int>
und is_reference<int>
false
ausgegeben. Da es sich bei den Funktionen um Templates handelt, findet keine Berechnung zur Laufzeit statt. Das Beispielprogramm verhält sich als wäre true
und false
in den verschiedenen Zeilen direkt angegeben worden.
Im Beispiel 48.1 war das Ergebnis der verschiedenen Funktionen ein bool
-Wert. Dieser konnte direkt auf die Standardausgabe ausgegeben werden. Soll ein Ergebnis von einer Template-Funktion weiterverarbeitet werden, darf es nicht als bool
-Wert vorliegen, sondern muss ein Typ sein.
boost::true_type
und boost::false_type
#include <boost/type_traits.hpp>
#include <iostream>
using namespace boost;
int main()
{
std::cout.setf(std::ios::boolalpha);
std::cout << is_same<is_integral<int>::type, true_type>::value << '\n';
std::cout << is_same<is_floating_point<int>::type, false_type>::value <<
'\n';
std::cout << is_same<is_arithmetic<int>::type, true_type>::value << '\n';
std::cout << is_same<is_reference<int>::type, false_type>::value << '\n';
}
Neben value bieten die Funktionen von Boost.TypeTraits das Ergebnis auch in type
an. Während value ein bool
-Wert ist, ist type
ein Typ. So wie es bei value nur zwei Werte gibt – true
oder false
– gibt es auch bei type
nur zwei Ergebnistypen: boost::true_type
oder boost::false_type
. Dank type
ist es möglich, das Ergebnis einer Funktion als Typ an eine andere Funktion zu übergeben.
Im Beispiel 48.2 wird mit boost::is_same
eine weitere Funktion von Boost.TypeTraits verwendet. Diese Funktion erwartet zwei Typen als Parameter und überprüft, ob es sich dabei um die gleichen Typen handelt. Um die Ergebnisse von boost::is_integral
, boost::is_floating_point
, boost::is_arithmetic
und boost::is_reference
an boost::is_same
übergeben zu können, muss auf type
zugegriffen werden. type
wird daraufhin mit boost::true_type
oder boost::false_type
verglichen. Die Ergebnisse von boost::is_same
werden wiederum über value entgegengenommen. Weil es sich dabei um einen bool
-Wert handelt, kann er auf die Standardausgabe ausgegeben werden.
#include <boost/type_traits.hpp>
#include <iostream>
using namespace boost;
int main()
{
std::cout.setf(std::ios::boolalpha);
std::cout << has_plus<int>::value << '\n';
std::cout << has_pre_increment<int>::value << '\n';
std::cout << has_trivial_copy<int>::value << '\n';
std::cout << has_virtual_destructor<int>::value << '\n';
}
Beispiel 48.3 stellt einige Funktionen vor, mit denen Eigenschaften von Typen abgefragt werden können. boost::has_plus
überprüft, ob ein Typ den Operator operator+
unterstützt und sich somit zwei Objekte des gleichen Typs verknüpfen lassen. boost::has_pre_increment
gibt an, ob ein Typ den Prä-Inkrement-Operator operator++
unterstützt. Mit boost::has_trivial_copy
kann ermittelt werden, ob ein Typ einen trivialen Copy-Konstruktor hat. Und mit boost::has_virtual_destructor
kann überprüft werden, ob ein Typ einen virtuellen Destructor hat.
Wenn Sie Beispiel 48.3 ausführen, wird dreimal true
und einmal false
ausgegeben.
#include <boost/type_traits.hpp>
#include <iostream>
using namespace boost;
int main()
{
std::cout.setf(std::ios::boolalpha);
std::cout << is_const<add_const<int>::type>::value << '\n';
std::cout << is_same<remove_pointer<int*>::type, int>::value << '\n';
std::cout << is_same<make_unsigned<int>::type, unsigned int>::value <<
'\n';
std::cout << is_same<add_rvalue_reference<int>::type, int&&>::value <<
'\n';
}
Beispiel 48.4 zeigt Ihnen, wie Sie Typ-Eigenschaften ändern. So wird einem Typ zum Beispiel mit boost::add_const
ein const
hinzugefügt. Ist ein Typ bereits konstant, ändert sich nichts. Der Code kompiliert problemlos, und der Typ bleibt konstant.
boost::remove_pointer
entfernt das Sternchen von einem Zeiger und gibt den Typ zurück, auf den der Zeiger zeigt. boost::make_unsigned
macht aus einem Typ einen ohne Vorzeichen. Und boost::add_rvalue_reference
wandelt einen Typ in eine Rvalue-Referenz um.
Wenn Sie Beispiel 48.4 ausführen, wird viermal true
ausgegeben.