Seite wählen

Unterschiedliche Datentypen mit boost::variant

von | Mrz 19, 2015 | Development

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.

0 Kommentare

Trackbacks/Pingbacks

  1. Monthly Snap March: boost::variant, blktrace, Logstash, Icinga 2.3, Icinga Camp › NETWAYS Blog - […] had a lot of super interesting posts in our blog, starting with Gunnar, who wrote something about different data…

Einen Kommentar abschicken

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert

Mehr Beiträge zum Thema Development

Mein PHP-Trainingsprojekt

PHP Schulung Vor kurzem haben wir begonnen, eine neue Programmiersprache zu lernen – PHP. In der ersten Woche haben wir mit den Grundlagen wie Variablen, Arrays, Schleifen begonnen und uns schrittweise zu komplizierterer Syntax wie Funktionen, Objekten und Klassen...

check_prometheus ist jetzt öffentlich verfügbar!

Monitoring ist komplex, das wissen wir hier bei NETWAYS leider zu gut. Deswegen laufen in der Infrastruktur auch mal gerne mehrere Tools für die Überwachung. Zwei gern gesehene Kandidaten sind dabei Icinga und Prometheus. Icinga und Prometheus erfüllen...