In C++ gibt es Fälle, in denen eine Funktion Werte zurückliefern soll, die nicht alle denselben Datentyp besitzen. Ein Beispiel hierfür ist eine Funktion, die einen JSON-String parsen soll und den deserialisierten Wert zurückgeben soll:

<Datentyp?> JsonDeserialize(const std::string& json);

Wenn wir die Funktion in C schreiben würden, könnten wir uns mit einem einfachen Trick behelfen: wir verwenden ein “Tagged Union” – also ein Union, zu dem wir uns zusätzlich merken, welches Feld darin aktuell gültig ist:

typedef struct {
  int tag; /* Das aktuell gültige Feld in dem Union */

  union {
    double value_double;
    char *value_string;
    ...
  };
} my_variant;

Mit C++ würde dies allerdings nicht funktionieren, da in einem Union nur POD-Typen erlaubt sind – also Datentypen, die keine Konstruktoren, Destruktoren oder andere Methoden enthalten. Der Hintergrund dabei ist, dass C++ nicht entscheiden kann, welchen Konstruktor und Destruktor es für das Union aufrufen soll, da es nicht weiss, welches Feld gültig ist.

Die Boost-Library bietet für dieses Problem eine elegante Lösung an: das boost::variant-Template kann verwendet werden, um eigene Typen zu definieren, die sich wie unser my_variant-Struct verhalten, aber zusätzlich auch nicht-triviale Typen (mit Konstruktor, Destruktor, usw.) enthalten kann:

typedef boost::variant<double, std::string, ...> my_variant;

Der my_variant-Typ verfügt dabei für jeden angegebenen Template-Parameter über einen passenden Konstruktor, der eine einfache Zuweisung erlaubt:

my_variant val = 7;

In diesem Fall wird der interne Typ des Variants auf “double” gesetzt und der Wert 7 gespeichert.

Um zu prüfen, welchen Typ ein Variant-Wert hat, kann die Methode “which” verwendet werden. Sie liefert einen null-basierten Index in die Template-Parameter zurück. Mit boost::get kann der Wert eines Variants extrahiert werden:

double dval = boost::get<double>(val);

Alternativ (und von der Boost-Dokumentation vorgeschlagen) kann auch das Visitor-Pattern verwendet werden, um auf die eigentlichen Werte zuzugreifen. Mehr Informationen gibt es in der Boost-Dokumentation.

Gunnar Beutner

Autor: Gunnar Beutner

Vor seinem Eintritt bei NETWAYS arbeitete Gunnar bei einem großen deutschen Hostingprovider, wo er bereits viel Erfahrung in der Softwareentwicklung für das Servermanagement sammeln konnte. Bei uns kümmert er sich vor allem um verschiedene Kundenprojekte, aber auch eigene Tools wie inGraph oder Icinga2.