Flexible convertir entre string, int, double pour le C++ Variante de la Classe
Je me suis mise en œuvre d'une variante de la classe (pas d'utilisation de boost) et je me demandais comment vous pouvez gérer le cas où vous auriez magasin tout de chaîne de caractères, entier, ou double et de les convertir automatiquement en fonction de type désiré par ToString(), ToInt(), ou ToDouble().
Par exemple,
Variant a = 7;
cout << "The answer is" + a.ToString() << endl; //should print "The answer is 7"
a = "7.4";
double &b = a.ToDouble();
b += 1;
cout << a.ToString() << endl; //should print 8.4
ToXXX
les fonctions de retour à la référence de la catégorie que vous souhaitez convertir. Maintenant, j'ai le code où il peut renvoyer le même type qu'il a été initialement attribué à( Variant a = Int(7); a.ToInt()
œuvres) et raise exception lorsque le assignée type est différent de celui que vous souhaitez convertir.
Désolé d'utilisation de boost n'est pas une option.
J'ai personnalisé les types de
String
, Int
, Double
que toutes dérive à partir d'un objet de base de classe. a.ToDouble()
serait effectivement de retour Double
mais je n'ai remplacer opérateur de cast pour Double
qui serait effectivement de retour de référence pour la double
.Bien sûr vous pouvez. Pensez Boost.Tout. - Je soupçonne que la réponse pourrait être que vous aurez besoin de mettre en œuvre la conversion de chacun de ces types dans chaque de la Chaîne, Int et Double classes.
pour une raison que j'ai pris le string/int/double locaux à l'objet. Je ne sais pas pourquoi, je suppose que. Semble stupide, avec le recul.
la variante est conçu comme un typesafe version d'un syndicat, afin de travailler avec différents types de manière uniforme, il n'est pas prévu pour de réinterprétation.
OriginalL'auteur JosephH | 2011-11-17
Vous devez vous connecter pour publier un commentaire.
C'est dangereux, il manque un constructeur par copie qui imite l'opérateur d'affectation. Voir le en.wikipedia.org/wiki/Rule_of_three_(C++_programming)
vous avez raison. c'est une version simplifiée. Il convient d'ajouter le constructeur de copie, de toute façon
Le constructeur de copie est toujours pas à l'abri parce que
*this
a complètement initialisée membres au moment de l'attribution. Sitype
arrive d'être à la CHAÎNE, cela va mal se passer.OriginalL'auteur BruceAdi
À mettre en place quelque chose comme cela, vous devez être en mesure de changer le stockée type, parce que si l'utilisateur modifie la variable par référence, il veut le changement d'affecter la valeur stockée, alors j'aimerais écrire quelque chose comme ceci:
String
comme unenum
valeur. La plupart des gens, que ce soit un préfixe ou un suffixe du type enum.StringType
ou quelque chose.OriginalL'auteur Evan Dark
J'ai mis en oeuvre une simple variante de la classe moi-même (sans l'aide de tiers libs). Chacun des
ToXxx
fonctions contient unswitch
surm_type
(enum qui indique le type actuellement en cours). Pour la conversion de chaîne de caractères (de et) j'utilisestd::stringstream
. Il est trivial, vraiment. Un peu comme Meuglement de Canard suggéré.P. S. Si fréquent d'appel de conversion de chaîne de caractères pour la même valeur est prévu, je serais en cache.
OriginalL'auteur Violet Giraffe
Tout d'abord, avez-vous absolument besoin de retour par référence? Retour par valeur serait probablement plus facile, car vous pourriez le faire à tout moment sans avoir à modifier l'état interne de l'objet Variant.
Si vous avez absolument besoin de retour par référence, alors vous devez avoir un valide emplacement de mémoire pour renvoyer une référence. (Ainsi, par exemple, renvoie une référence à une pile d'objet n'est pas bon, parce que la pile de l'objet aurait disparu lors de la ToXXX() la méthode retourne, et la référence pourrait être une référence à une mémoire non valide)
Le moyen facile de le faire serait d'ajouter un (mutable?) variable de membre de chaque type dans votre Variante de l'objet, et de définir cette variable membre de la valeur et de renvoyer une référence en tant que de besoin. Bien sûr que l'inconvénient de cette méthode est qu'elle permet à votre Variante objets aussi grand que la somme de tous les objets, mais qui pourrait être bien si vous ne vous souciez pas beaucoup au sujet de l'utilisation de la mémoire.
Si vous ne vous souciez de minimiser l'utilisation de la mémoire de votre Variante objets aussi, alors vous aurez probablement besoin d'utiliser un syndicat (ou quelque chose d'équivalent à un). C syndicats de travail pour les POD types, mais si vous avez besoin d'inclure des non-POD types (par exemple std::string objets) qu'ils ne seront pas suffisantes. Si vous avez besoin, vous pouvez aller avec un octet de la mémoire tampon (qui est assez grand pour le plus grand type d'ajustement) et l'aide au placement de nouvelles et destructeur explicite des appels lorsque cela est nécessaire, mais il est un peu délicate à mettre en œuvre.
Autant que les conversions de types de données (par exemple, "7" -> (int)7 -> (double)7.0, vous devez simplement mettre en œuvre une logique (peut-être par imbriqués les instructions switch?) pour faire la bonne chose pour chaque paire possible de "source" et "destination". Je ne pense pas qu'il y est de la magie chemin autour de cela, bref de l'aide de stimuler la fonctionnalité, où il a été fait pour vous.
OriginalL'auteur Jeremy Friesner
C'est la seule façon que je peux penser, si vous voulez être en mesure de convertir à la volée.
union
complexités que la mienne. Faire à la place.OriginalL'auteur Mooing Duck
Voici un moyen rapide et sale de la mise en œuvre à l'aide de boost::any que la valeur titulaire à la place de classes personnalisées. Comme vous pouvez le voir, les modèles peuvent aider un peu pour garder la quantité de code un peu plus courte.
ToXXX fonctions de changer le type sous-jacent de la valeur stockée (sauf si aucune conversion n'est nécessaire), puis renvoyer une référence. Les Conversions sont effectuées à l'aide boost::lexical_cast, qui ne peut être entièrement adapté à vos besoins (il lève des exceptions si les conversions ne sont pas une réussite, selon lexical_cast de conditions très strictes).
(En action: http://codepad.org/C3l5AXg3)
La mise en œuvre pourrait être encore plus simple avec
boost::variant<int, double, std::string>
, comme vous pourriez être en mesure de le retirer avec un seul visiteur basé sur un modèleoperator()
au lieu d'avoir à écrire un code distinct chemin d'accès pour chacun des différents types.ToSomething()
fonctions de la mutation en général. Ni il est viable approche de la conception, par exempleVariant v("abc"); v.ToDouble();
.Oui, il peut être une mauvaise idée, mais c'est ce que vous avez à faire afin de répondre aux exigences de l'utilisation des exemples de code. - Quant à la contre-exemple, ce sera juste jeter une erreur (bad_lexical_cast, mais vous pouvez l'attraper et de le remplacer par votre propre erreur). Quoi d'autre serait une classe conçue de cette façon?
Je ne dis pas que les autres solutions sont mieux, je suis en train de dire toute solution est mauvaise parce que les exigences de conception sont imparfaits.
Oui, je serais d'accord avec ça.
boost::lexical_cast<T>
ne compile pas sur VS2010. Malheureusement, il semble que vous devez avoir un objectif explicite de type à éviter pas acceptable des erreurs de conversion.OriginalL'auteur UncleBens
Juste pour savoir que C++17 va mettre en œuvre un std::variante pour ce faire.
OriginalL'auteur Pedro Reis
Compte tenu de ce que vous avez besoin, je suggère de télécharger http://qt.nokia.com et à la recherche dans une mise en œuvre de QVariant Classe. Si cela vous semble trop compliqué, je dirais quelque chose comme ceci:
La mise en œuvre de la conversion devrait être simple à partir d'ici.
Si vous souhaitez plus simple et la performance n'est pas une préoccupation majeure des données stockées dans la variante pourrait être converti en chaîne de caractères, puis convertie en arrière lorsque la méthode est appelée.
Si vous avez besoin de détails de mise en œuvre pour les fonctions de conversion je peux les fournir, mais je pense qu'ils devraient être assez simple.
To
-méthodes retournent des références (et qui font de l'ensemble du sujet beaucoup plus compliqué puisque la modification de la référence doit changer toutes les représentations.)Assez vrai, mais personnellement, je ne vois pas de raison de le faire que beaucoup plus compliqué alors qu'il doit être. Le seul retour qu'une référence de retour serait avantageux pour est les chaînes.
Vous devriez lire de nouveau la question. C'est une exigence que la valeur stockée peut être modifié par modifié le retourné de référence.
OriginalL'auteur Karlson