c++ stringstream à ostream à chaîne
Je voudrais être capable de faire:
foo(stringstream()<<"number = " << 500);
EDIT: la seule solution en ligne est cruciale, car c'est à des fins de journalisation. Ces derniers seront tout autour du code.
à l'intérieur de foo affichera la chaîne à l'écran ou quelque chose du genre.
maintenant depuis stringstream de l'opérateur<< retourne ostream&, foo signature doit être:
foo(ostream& o);
mais comment puis-je convertir ostream& string? (ou char*).
Des approches différentes à la réalisation de ce cas d'utilisation sont les bienvenus.
Ne
pour avoir tous les travaux en une seule ligne, je crois qu'il n'
Ne pouvez-vous pas créer une macro pour cela, puisque c'est du C++? Ensuite, vous avez
Vous pouvez toujours
Vous pourriez envisager d'utiliser un string builder.
foo
vraiment besoin de prendre une ostream &
? Ou serait-il acceptable que si elle prend un stringstream &
ou peut-être un std::string const &
?pour avoir tous les travaux en une seule ligne, je crois qu'il n'
Ne pouvez-vous pas créer une macro pour cela, puisque c'est du C++? Ensuite, vous avez
foo(MACRO_NAME("number = " << 500))
.Vous pouvez toujours
static_cast
(ou dynamic_cast
si vous voulez être sûr) o
à stringstream
à l'intérieur de foo
.Vous pourriez envisager d'utiliser un string builder.
OriginalL'auteur Leo | 2011-11-02
Vous devez vous connecter pour publier un commentaire.
La solution la plus évidente consiste à utiliser
dynamic_cast
dansfoo
. Mais lele code ne fonctionne toujours pas. (Votre exemple de la compilation, mais il ne fera pas ce
vous pensez qu'il devrait.) L'expression
std::ostringstream()
est untemporaire, vous ne pouvez pas initialiser un non-const de référence avec une temporaire,
et le premier argument de
std::operator<<( std::ostream&, char const*)
est un non-const de référence. (Vous pouvez appeler une fonction membre sur un
temporaire. Comme
std::ostream::operator<<( void const* )
. Donc le codecompiler, mais il ne fera pas ce que vous attendez.
Vous pouvez contourner ce problème, en utilisant quelque chose comme:
std::ostream::flush()
retourne un non-const de référence, donc il n'y a pasd'autres problèmes. Et sur un fraîchement créé des flux, c'est un no-op.
Pourtant, je pense que vous serez d'accord que ce n'est pas la plus élégante ou intuitive
solution.
Ce que je fais habituellement dans de tels cas est de créer une classe wrapper, qui
contient sa propre
std::ostringstream
, et fournit basé sur un modèlemembre
operator<<
qui les transmet à l'std::ostringstream
. Votre fonctionfoo
prendrait unconst
la référence à la présente ou de ce que je offen n'ont qu'à appeler le destructeur
foo
directement, de sorte que le code du client n'avez même pas à vous soucier deil; elle fait quelque chose comme:
La fonction
log()
retourne une instance de la classe wrapper (mais voirci-dessous), et la version finale du destructeur de cette classe appelle votre fonction
foo
.Il y a un léger problème avec cela. La valeur de retour peut être copié,
et détruits immédiatement après la copie. Qui fera des ravages avec
ce que je viens de l'expliquer; en fait, depuis
std::ostringstream
n'est-ce pascopiable, il ne sera même pas compiler. La solution ici est de mettre toutes les
logique réelle, y compris l'instance de
std::ostringstream
et ladestructeur de logique d'appel
foo
dans une autre mise en œuvre de la classe,le public wrapper ont un
boost::shared_ptr
, et en avant. Oujuste réimplémenter un peu de le pointeur partagé logique dans votre classe:
Remarque qu'il est facile d'étendre à d'appui en option de journalisation; juste
fournir un constructeur de la LogWrapper qui définit
collector
àNULL
, et de le tester dans leoperator<<
.ÉDITÉ:
Une autre chose me vient à l'esprit: vous aurez probablement envie de vérifier si l'
le destructeur est appelé comme un résultat d'une exception, et de ne pas appeler
foo
dans ce cas. Logiquement, j'espère que la seule exception que vouspourrait
std::bad_alloc
, mais il y aura toujours un utilisateur quiécrit quelque chose comme:
où la
+
est un définis par l'utilisateur de la surcharge qui en jette.LogWrapper
objets de réutiliser le mêmeostringstream
. Que de la modifier, comment vous y prendriez-vous pour détecter si nous sommes dénouement de la pile?+1. Brillante Explication. 🙂
admettre que, dans la pratique, j'ai rarement la peine. Mais depuis que je suis en postant ce qui est censé être un bon exemple, je pourrais aussi bien essayer d'être aussi exactes que possible.)
Le principal inconvénient de ceci semble être qu'il étroitement les couples de la chaîne de construction avec l'utilisation de la chaîne finale; l'appel de
foo
de le destructeur ne fait pas cette approche terriblement réutilisables.Encore, l'approche est appropriée pour l'usage en question, et la généralisation d'appeler n'importe quel autre code est simple (juste un magasin
std::/boost::function<void(std::string)>
passé dans le constructeur de l'appel à la fin.OriginalL'auteur James Kanze
Vous pouvez utiliser un objet proxy pour cela, c'est un peu du cadre, mais si vous souhaitez utiliser cette notation dans beaucoup d'endroits, alors il peut être vaut la peine:
Ce programme imprime
L'idée est d'avoir un peu de classe wrapper qui peut être implicitement converti en un
std::string
. Le<<
opérateur est simplement transmis le contenu de l'std::stringstream
. Lemake_stream()
fonction n'est pas strictement nécessaire (on pourrait aussi dire queStreamProxy()
, mais j'ai pensé qu'il ressemble un peu mieux.operator<<
avec une temporaireStreamProxy
.Vous pouvez créer un objet singleton et clair, il est contenu dans
operator std::string
. Mais je ne sais pas si c'est bon 😉Kanze: je n'ai rapidement essayé avec MSVC6 (ouais, ouais, je sais...) en attendant un autre build. Il est en effet possible qu'il existe d'autres problèmes. J'espère que j'ai eu l'idée générale à travers. 🙂
Je crains que même les versions plus récentes de VC++ ne parviennent pas à respecter cette règle. La plupart des autres compilateurs faire, cependant.
C'est précisément la raison pour laquelle j'ai fait
operator<<
une fonction membre de lastringbuilder
dans ma solution. Je fais référence à votre premier commentaire :-).OriginalL'auteur Frerich Raabe
Je vous suggère d'utiliser cet utilitaire struct:
Et l'utiliser comme:
Démo (avec quelques exemple) : http://ideone.com/J995r
Plus sur mon blog : Créer des chaînes à la volée juste en une seule ligne
OriginalL'auteur Nawaz
Un couple d'options autres que la belle proxy solution présentée par Frerich Raabe:
Définir une chaîne statique flux variable dans l'en-tête qui définit la fonction de journalisation et de l'utilisation de l'opérateur virgule dans votre invocation de la fonction de journalisation, de sorte que cette variable est passé plutôt que
ostream&
retourné par le flux opérateur d'insertion. Vous pouvez utiliser un enregistrement de macro pour masquer cette laideur. Le problème avec cette solution est qu'il est un peu sur le côté laid, mais c'est une méthode communément utilisée pour l'enregistrement.N'utilisez pas le C++ I/O. l'Utilisation d'un varargs de style C solution à la place. Passer une chaîne de format comme le premier argument, avec les arguments restants étant des cibles pour que la chaîne de format. Un problème avec cette solution est que même si votre compilateur est assez intelligent pour s'assurer que
printf
et ses cousins sont en sécurité, le compilateur ne saura probablement pas que cette nouvelle fonction est une partie de laprintf
de la famille. Néanmoins, c'est aussi une approche communément utilisée.OriginalL'auteur David Hammen
Si vous n'avez pas l'esprit à l'aide de macros fonctions, vous pouvez faire de la fonction d'enregistrement accepter
const string&
, et utiliser la macro suivanteEt supposons que vous
foo
a la signaturevoid foo(const string&)
, vous avez seulement besoin du one-linerCela a été inspiré par James Kanze réponse sur
static_cast
etstringstream.flush
. Sans le.flush()
la méthode ci-dessus échoue avec inattendus de sortie.Veuillez noter que cette méthode ne doit pas présenter une fuite de mémoire, comme des valeurs temporaires, que ce soit dans le pointeur en forme ou pas, sont toujours allouées sur la pile, et donc détruit lors de la restitution.
OriginalL'auteur Interarticle
Puisque vous êtes à la conversion de la chaîne de toute façon, pourquoi ne pas
alors s'il vous plaît mentionner que vous voulez en faire un one-liner en premier lieu.
édité, désolé pour le retard
OriginalL'auteur hochl
Ce n'est pas possible. Comme son nom l'
ostream
l'indique, il est utilisé pour la sortie, pour l'écriture. Vous pouvez modifier le paramètre destringstream&
. Cette classe est la méthodestr()
qui renvoie unestd::string
pour votre utilisation.MODIFIER je n'ai pas lu la question avec
operator <<
retourostream&
. Donc je suppose que vous ne pouvez pas simplement écrire vos instructions dans les fonctions de la liste d'arguments, mais d'avoir à l'écrire avant.Ce qui est vrai. Peut-être que vous pourriez lancer la référence à l'intérieur de
foo
mais je ne suis pas sûr si c'est possible avec les descendants destd::ostream
.OriginalL'auteur Constantinius
Vous pouvez créer un petit wrapper autour de
std::ostringstream
qui va convertir le retour àstd::string
sur l'utilisation, et ont pour fonction de prendre unstd::string const &
. La première approche de cette solution peut être trouvée dans cette réponse à une question différente.En plus de cela, vous pouvez ajouter le support pour les manipulateurs (
std::hex
) si nécessaire.operator<<
doit être un membre, bien sûr (ou vous pouvez mentir un peu surconst
-ness, faireoperator<<
prendre const référence à l'emballage).OriginalL'auteur David Rodríguez - dribeas