Domanda

Io sono nel processo di creazione di una classe che memorizza i metadati relativi a una particolare fonte di dati.I metadati è strutturato in un albero, molto simile a come XML è strutturato.I valori dei metadati può essere un numero intero o decimale, o valori di stringa.

Sono curioso di sapere se c'è un buon modo in C++ per memorizzare i dati delle varianti per una situazione come questa.Mi piacerebbe per la variante di usare librerie standard, quindi sto evitando di COM, Ole e SQL tipi di VARIANTE di che sono disponibili.

La mia soluzione attuale è qualcosa di simile a questo:

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;
};

Il MetaValue classe ha diverse funzioni Get per ottenere attualmente memorizzati variante di valore, ma si finisce per fare ogni query per un valore di un grosso blocco di if/else, se le istruzioni per capire il valore che sto cercando.

Ho esplorato anche memorizzare il valore come solo una stringa, e di eseguire conversioni per ottenere diversi tipi di variante, ma per quanto ho visto questo porta ad un sacco di stringhe interno l'analisi e la gestione degli errori che non è abbastanza, si apre un grande vecchio grado di precisione e di problemi di perdita di dati con valori a virgola mobile, e ancora non elimina la query if/else se il problema sopra indicato.

Qualcuno ha implementato o visto qualcosa che il detergente da utilizzare per un C++ tipo di dati variant utilizzando librerie standard?

È stato utile?

Soluzione

Come di C++17, c'è std::variant.

Se non è possibile utilizzare che di sicurezza, si potrebbe desiderare Boost.Variante.Simili, ma distinti, tipo per la modellazione di polimorfismo è fornito dalla std::any (e, pre-C++17, Boost.Qualsiasi).

Come puntatore, è possibile cercare “tipo di cancellazione”.

Altri suggerimenti

Mentre Konrad risposta (usare una soluzione standardizzata) è sicuramente preferibile scrivere la propria soggetta a bug della versione, il boost variante ha alcune spese generali, in particolare in costruzione per copia e di memoria.

Un comune approccio personalizzato è modificata seguente Modello Factory:

  1. Creare una interfaccia di Base di un generico oggetto che incapsula anche il tipo di oggetto (come un enum), oppure l'uso di typeid' (preferibile).
  2. Ora implementare l'interfaccia utilizzando un modello Derived classe.
  3. Creare una classe factory con un templateized create con funzione di firma:

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

Questo internamente crea un Derived<_T> oggetto sullo heap, e retuns un cast dinamico puntatore.Specializzati questo per ogni classe che si desidera implementare.

Infine, la definizione di una Variant wrapper che contiene questo Base * puntatore e definisce il modello le funzioni get e set.Funzioni di utilità come getType(), isEmpty(), di cessione e operatori di uguaglianza, ecc possono essere opportunamente implementato qui.

A seconda delle funzioni di utilità e la fabbrica di attuazione, supportato classi sarà necessario il supporto di alcune funzioni di base come l'assegnazione o la copia di costruzione.

Si può anche andare giù per un C-ish soluzione, che avrebbe un void* la dimensione di un doppio nel sistema, oltre a una enum per il tipo che si sta utilizzando.È ragionevolmente pulito, ma sicuramente una soluzione per qualcuno che si sente del tutto confortevole, con il raw byte del sistema.

C++17 ora ha std::variant che è esattamente quello che stai cercando.

std::variante

Anche se la questione era stata risolta per un lungo periodo di tempo, per la cronaca, vorrei ricordare che QVariant fa anche questo.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top