Frage

Ich bin im Begriff, eine Klasse zu erstellen, die Metadaten zu einer bestimmten Datenquelle speichert. Die Metadaten werden in einem Baum strukturiert, sehr ähnlich wie XML strukturiert ist. Die Metadatenwerte können integer, decimal oder String-Werte sein.

Ich bin gespannt, ob es eine gute Möglichkeit, in C ++ ist Variant-Daten, wie dies für eine Situation zu speichern. Ich möchte mich für die Variante Standardbibliotheken zu verwenden, so dass ich die Vermeidung der COM, Ole und SQL-VARIANT-Typen, die verfügbar sind.

Meine aktuelle Lösung sieht ungefähr wie folgt aus:

enum MetaValueType
{
    MetaChar,
    MetaString,
    MetaShort,
    MetaInt,
    MetaFloat,
    MetaDouble
};

union MetaUnion
{
    char cValue;
    short sValue;
    int iValue;
    float fValue;
    double dValue;
};

class MetaValue
{
...
private:
    MetaValueType ValueType;
    std::string StringValue;
    MetaUnion VariantValue;
};

Die metavalue Klasse hat verschiedene Funktionen Holen Sie sich für den aktuell gespeicherten Variante Wert zu erhalten, aber es endet macht jede Abfrage für einen Wert, der einen großen Block von if / else if-Anweisungen, um herauszufinden, welchen Wert ich suche.

Ich habe untersucht auch den Wert als nur einen String zu speichern und Ausführen Konvertierungen aus verschiedenen Variantentypen zu bekommen, aber soweit ich dies führt zu einer Reihe von interner String-Analyse und Fehlerbehandlung, die nicht gesehen habe, ist hübsch, öffnet sich eine große alte Dose Präzision und Datenverlust Probleme mit Gleitkommazahlen, und immer noch die Abfrage nicht, wenn / sonst nicht beseitigt, wenn Ausgabe oben angegeben.

Hat jemand implementiert oder etwas gesehen, das saubere ist für einen C ++ Variant-Datentyp zu verwenden, unter Verwendung von Standard-Bibliotheken?

War es hilfreich?

Lösung

Wie von C ++ 17, gibt es std::variant .

Wenn Sie nicht verwenden können, dass noch wollen Sie vielleicht Boost.Variant . Ein ähnlicher, aber deutlich, Typ für die Modellierung von std::any (und , pre-C 17 ++ Boost.Any ).

Nur als zusätzliche Zeiger, können Sie sich für „ Typ Löschung “.

Andere Tipps

Während Konrad Antwort (eine bestehende standardisierte Lösung mit) Ihre eigenen Fehler anfällige Version zu schreiben sicherlich vorzuziehen ist, die Boost-Variante einige Gemeinkosten, vor allem in Kopie Bau und Speicher.

Ein gemeinsamer maßgeschneiderter Ansatz ist das folgende modifizierte Factory-Muster:

  1. Erstellen Sie eine Base-Schnittstelle für ein generisches Objekt, das auch den Objekttyp (entweder als ENUM) oder mit ‚typeid‘ (bevorzugt).
  2. verkapselt
  3. Nun implementieren die Schnittstelle eine Vorlage Derived Klasse.
  4. Erstellen Sie eine Factory-Klasse mit einer templateized create Funktion mit Unterschrift:

template <typename _T> Base * Factory::create ();

Dieses intern erstellt ein Derived<_T> Objekt auf dem Heap und Retuns einen dynamischen Guss Zeiger. Spezialisieren Sie dies für jede Klasse, die Sie implementiert werden soll.

Schließlich definiert eine Variant Wrapper, der diesen Base * Zeiger enthält und definiert Funktionen Vorlage abrufen und festlegen. Utility-Funktionen wie getType(), isEmpty(), Zuordnung und Gleichheitsoperatoren, usw. können in geeigneter Weise hier realisiert werden.

Abhängig von den Utility-Funktionen und die Fabrik Umsetzung unterstützte Klassen müssen einige grundlegende Funktionen wie Zuordnung oder Kopie Bau unterstützen.

Sie können auch zu einer C-ish Lösung gehen, die eine void * die Größe eines Doppels auf Ihrem System haben würde, sowie eine ENUM für welche Art Sie verwenden. Es ist recht sauber, aber auf jeden Fall eine Lösung für jemanden, der mit dem rohen Bytes des Systems ganz wohl fühlt.

C ++ 17 jetzt hat std::variant das ist genau das, was Sie suchen.

std :: Variante

Auch wenn die Frage für eine lange Zeit beantwortet worden ist, für die Aufzeichnung würde Ich mag, dass

scroll top