Question

Je suis en train de créer une classe qui stocke des métadonnées sur une source de données particulière. Les métadonnées sont structurées dans un arbre, très similaire à la structure de XML. Les valeurs de métadonnées peuvent être des valeurs entières, décimales ou chaîne.

Je suis curieux de savoir s'il existe un bon moyen en C ++ de stocker des données de variante pour une situation comme celle-ci. J'aimerais que la variante utilise des bibliothèques standard, j'évite donc les types VARIANT COM, Ole et SQL disponibles.

Ma solution actuelle ressemble à ceci:

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

La classe MetaValue dispose de diverses fonctions Get permettant d’obtenir la valeur de variante actuellement stockée, mais chaque requête de valeur est transformée en un gros bloc d’instructions if / else if pour déterminer la valeur que je recherche.

J'ai également envisagé de stocker la valeur sous forme de chaîne uniquement et d'effectuer des conversions pour obtenir différents types de variantes, mais autant que je sache, cela conduit à une série d'analyses internes de chaînes et à la gestion des erreurs, joli, ouvre une grosse boîte de problèmes de précision et de perte de données avec des valeurs à virgule flottante, et n'élimine toujours pas la requête if / else si le problème mentionné ci-dessus.

Quelqu'un at-il implémenté ou vu quelque chose de plus propre à utiliser pour un type de données variant C ++ à l'aide de bibliothèques standard?

Était-ce utile?

La solution

À partir de C ++ 17, il existe std :: variant .

Si vous ne pouvez pas encore l'utiliser, vous voudrez peut-être Boost.Variant . Un type similaire mais distinct pour la modélisation du polymorphisme est fourni par std :: any (et, avant C ++ 17, Boost.Any ).

Comme pointeur supplémentaire, vous pouvez rechercher « type effacement ».

Autres conseils

Bien que la réponse de Konrad (utilisant une solution standardisée existante) soit certainement préférable à l'écriture de votre propre version sujette aux bogues, la variante boost subit quelques surcoûts, en particulier pour la construction de copie et la mémoire.

Une approche personnalisée commune est le modèle d'usine modifié suivant:

  1. Créez une interface de base pour un objet générique qui encapsule également le type d'objet (sous forme d'énumération) ou à l'aide de 'typeid' (préférable).
  2. Maintenant, implémentez l'interface en utilisant une classe de modèle Derived .
  3. Créer une classe de fabrique avec une fonction create modélisée avec signature:

modèle < typename _T > Base * Factory :: create ();

Ceci crée en interne un objet dérivé sur le segment de mémoire et relance un pointeur de conversion dynamique. Spécialisez ceci pour chaque classe que vous souhaitez implémenter.

Enfin, définissez un wrapper Variant contenant ce pointeur Base * et définissant les fonctions de modèle et d'objet. Des fonctions utilitaires telles que getType () , isEmpty () , des opérateurs d'affectation et d'égalité, etc. peuvent être correctement implémentées ici.

En fonction des fonctions utilitaires et de l'implémentation usine, les classes prises en charge devront prendre en charge certaines fonctions de base telles que l'affectation ou la construction de copies.

Vous pouvez également passer à une solution plus C-ish, qui aurait un vide * de la taille d’un double sur votre système, plus une énumération pour le type que vous utilisez. C'est relativement propre, mais c'est certainement une solution pour quelqu'un qui se sent totalement à l'aise avec les octets bruts du système.

C ++ 17 a maintenant std :: variant , ce qui est exactement ce que vous recherchez.

std :: variant

Bien que la question ait été résolue depuis longtemps, je voudrais mentionner que QVariant effectue également cette opération.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top