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
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.
0 Kommentare
Trackbacks/Pingbacks