Die Boost C++ Bibliotheken

Kapitel 23. Boost.Any

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.

Beispiel 23.1. 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.

Beispiel 23.2. Einen String in 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.

Beispiel 23.3. Zugriff auf Werte mit 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.

Beispiel 23.4. 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.

Beispiel 23.5. Momentan gespeicherten Typ abfragen
#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.

Beispiel 23.6. Zugriff auf Werte über einen Zeiger
#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.