In strengtypisierten Sprachen wie C++ hat jede Variable einen ganz bestimmten Typ. Dieser Typ entscheidet darüber, welche Art von Daten in einer Variablen gespeichert werden können. Wer in einer Variablen eine beliebige Art von Daten speichern möchte, muss eine Programmiersprache wie beispielsweise JavaScript verwenden: Dort kann in einer Variablen ein String, danach eine Zahl und dann ein Wahrheitswert gespeichert werden. In JavaScript kann jede Variable Daten beliebiger Art speichern.
Die Bibliothek Boost.Any stellt eine Klasse boost::any
zur Verfügung, die es ähnlich wie in JavaScript in C++ ermöglicht, Daten beliebiger Art in einer entsprechenden Variablen zu speichern.
boost::any
in Aktion#include <boost/any.hpp>
int main()
{
boost::any a = 1;
a = 3.14;
a = true;
}
Um boost::any
verwenden zu können, muss die Headerdatei boost/any.hpp
eingebunden werden. Sie können dann Objekte vom Typ boost::any
erstellen, in denen Sie Daten beliebiger Art speichern können. So wird im Beispiel 23.1 in a zuerst ein int
-Wert, dann eine Kommazahl vom Typ double
und dann ein Wahrheitswert gespeichert.
Beachten Sie, dass es Mindestanforderungen gibt. So muss der Typ des Werts, der gespeichert werden soll, einen Copy-Konstruktor besitzen. Dies bedeutet beispielsweise, dass es nicht möglich ist, C-Arrays in einer boost::any
-Variablen zu speichern. Denn diese besitzen keinen Copy-Konstruktor.
Möchten Sie einen String in einer boost::any
-Variablen speichern und nicht lediglich einen Zeiger auf einen C-String, greifen Sie wie im Beispiel 23.2 explizit auf std::string
zu.
boost::any
speichern#include <boost/any.hpp>
#include <string>
int main()
{
boost::any a = std::string{"Boost"};
}
Um auf den Wert einer boost::any
-Variablen zuzugreifen, muss der Cast-Operator boost::any_cast
verwendet werden. Sehen Sie sich dazu Beispiel 23.3 an.
boost::any_cast
#include <boost/any.hpp>
#include <iostream>
int main()
{
boost::any a = 1;
std::cout << boost::any_cast<int>(a) << '\n';
a = 3.14;
std::cout << boost::any_cast<double>(a) << '\n';
a = true;
std::cout << std::boolalpha << boost::any_cast<bool>(a) << '\n';
}
Indem der entsprechende Typ als Template-Parameter an boost::any_cast
übergeben wird, wird der Wert der boost::any
-Variablen umgewandelt. Sollte ein ungültiger Typ angegeben werden und eine entsprechende Konvertierung nicht durchgeführt werden können, wird eine Ausnahme vom Typ boost::bad_any_cast
geworfen.
boost::bad_any_cast
bei fehlerhaftem Zugriff#include <boost/any.hpp>
#include <iostream>
int main()
{
try
{
boost::any a = 1;
std::cout << boost::any_cast<float>(a) << '\n';
}
catch (boost::bad_any_cast &e)
{
std::cerr << e.what() << '\n';
}
}
Im Beispiel 23.4 wird eine Ausnahme geworfen, weil der als Template-Parameter übergebene Typ float
nicht dem Typ int
entspricht, der in der Variablen a verwendet wird. Es ist wichtig, jeweils genau den Typ als Template-Parameter anzugeben, der in der entsprechenden boost::any
-Variablen verwendet wird. So würde Beispiel 23.4 auch dann eine Ausnahme werfen, wenn als Template-Parameter short
oder long
angegeben werden würde.
Da die Klasse boost::bad_any_cast
von std::bad_cast
abgeleitet ist, können Sie in catch
-Handlern auch Ausnahmen dieses Typs abfangen.
Möchten Sie wissen, ob in einer Variablen vom Typ boost::any
ein Wert gespeichert ist, können Sie die Methode empty()
aufrufen. Um zu erfahren, welchen Typ ein in boost::any
gespeicherter Wert besitzt, können Sie type()
verwenden.
#include <boost/any.hpp>
#include <typeinfo>
#include <iostream>
int main()
{
boost::any a = 1;
if (!a.empty())
{
const std::type_info &ti = a.type();
std::cout << ti.name() << '\n';
}
}
Im Beispiel 23.5 wird sowohl empty()
als auch type()
aufgerufen. Während empty()
einen Wahrheitswert zurückgibt, ist der Typ des Rückgabewerts von type()
die in der Headerdatei typeinfo
definierte Klasse std::type_info
.
Abschließend sehen Sie im Beispiel 23.6, wie Sie mit boost::any_cast
einen Zeiger auf einen Wert in einer boost::any
-Variable erhalten.
#include <boost/any.hpp>
#include <iostream>
int main()
{
boost::any a = 1;
int *i = boost::any_cast<int>(&a);
std::cout << *i << '\n';
}
Sie müssen lediglich einen Zeiger auf die boost::any
-Variable als Parameter an boost::any_cast
übergeben. Der Template-Parameter bleibt unverändert.