Question

Considérons la fonction suivante:

void f(const char* str);

Supposons que je veuille générer une chaîne en utilisant stringstream et le transmettre à cette fonction. Si je veux le faire dans une déclaration, je pourrais essayer:

f((std::ostringstream() << "Value: " << 5).str().c_str()); // error

Cela donne une erreur: « str () » est pas un membre de « basic_ostream ». OK, l'opérateur << est de retour ostream au lieu de ostringstream - Que diriez-vous le jeter retour à un ostringstream

1) Est-ce casting sûr?

f(static_cast<std::ostringstream&>(std::ostringstream() << "Value: " << 5).str().c_str()); // incorrect output

Maintenant, avec cela, il tourne pour l'opérateur << ( « Valeur ») appel, il est en fait d'appeler l'opérateur de ostream << (void * le) et l'impression d'une adresse hexadécimale. Ceci est faux, je veux que le texte.

2) Pourquoi l'opérateur << sur la std :: ostringstream temporaire () appeler l'opérateur ostream? Certes, le temporaire a un type de 'ostringstream' non 'ostream'?

Je peux lancer le temporaire pour forcer trop l'appel de l'opérateur correct!

f(static_cast<std::ostringstream&>(static_cast<std::ostringstream&>(std::ostringstream()) << "Value: " << 5).str().c_str());

Cela semble fonctionner et passe "Valeur: 5" à f ()

.

3) Est-ce que je comptais sur un comportement non défini maintenant? Les moulages semblent hors du commun.


Je suis au courant de la meilleure alternative est quelque chose comme ceci:

std::ostringstream ss;
ss << "Value: " << 5;
f(ss.str().c_str());

... mais je suis intéressé par le comportement de le faire en une seule ligne. Supposons que quelqu'un voulait faire un (douteux) macro:

#define make_temporary_cstr(x) (static_cast<std::ostringstream&>(static_cast<std::ostringstream&>(std::ostringstream()) << x).str().c_str())

// ...

f(make_temporary_cstr("Value: " << 5));

Est-ce que cette fonction comme prévu?

Était-ce utile?

La solution

Vous ne pouvez pas lancer le flux temporaire std::ostringstream&. Il est mal formé (le compilateur doit vous dire qu'il est faux). Ce qui suit peut le faire, bien que:

f(static_cast<std::ostringstream&>(
  std::ostringstream().seekp(0) << "Value: " << 5).str().c_str());

Ce bien sûr est laid. Mais il montre comment cela peut fonctionner. seekp est une fonction de renvoi d'un élément std::ostream&. Serait sans doute préférable d'écrire cette manière générale

template<typename T>
struct lval { T t; T &getlval() { return t; } };

f(static_cast<std::ostringstream&>(
  lval<std::ostringstream>().getlval() << "Value: " << 5).str().c_str());

La raison pour laquelle, sans tout ce qu'il faut le void*, est parce que operator<< est une fonction membre. Le operator<< qui prend char const* n'est pas.

Autres conseils

Un temporaire ne peut être passé comme une référence non-const à une fonction, c'est la raison pour laquelle il ne trouve pas l'opérateur de streaming correct et prend place celui avec vide l'argument * (il est fonction de membre et donc l'appeler sur une base temporaire est OK).

Ce qui vient à contourner les limites par coulée, j'ai le sentiment qu'il est en fait UB, mais je ne peux pas dire à coup sûr. Quelqu'un d'autre va sûrement citer la norme.

Cela peut être fait en utilisant une fonction C ++ 11 lambda.

#include <iostream>
#include <sstream>

void f(const char * str)
{
    std::cout << str << std::endl;
}

std::string str(void (*populate)(std::ostream &))
{
    std::ostringstream stream;
    populate(stream);
    return stream.str();
}

int main(int argc, char * * args)
{
    f(str([](std::ostream & ss){ ss << "Value: " << 5;  }).c_str());
    return 0;
}

// g++ -std=c++11 main.cpp -o main
// ./main
// Value: 5

Si vous aimez les déclarations one_lined vous pouvez écrire:

// void f(const char* str); 
f(static_cast<ostringstream*>(&(ostringstream() << "Value: " << 5))->str());

Cependant, vous devriez préférer plus facile à maintenir le code comme:

template <typename V>
  string NumberValue(V val)
  {
     ostringstream ss;
     ss << "Value: " << val;
     return ss.str();
  }
f(NumberValue(5));

J'utiliser quelque chose un peu comme ça pour l'exploitation forestière.

#include <sstream>

using namespace std;

const char *log_text(ostringstream &os, ostream &theSame)
{
  static string ret; // Static so it persists after the call
  ret = os.str();
  os.str(""); // Truncate so I can re-use the stream
  return ret.c_str();
}


int main(int argc, char **argv)
{
  ostringstream  ss;
  cout << log_text(ss, ss << "My first message") << endl;
  cout << log_text(ss, ss << "Another message") << endl;
}

Sortie:

Mon premier message

Un autre message

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