Pregunta

Considere la siguiente función:

void f(const char* str);

Supongamos que quiero generar una cadena usando stringstream y pasarlo a esta función. Si quiero hacerlo en un comunicado, que puede probar:

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

Esto da un error: 'str ()' no es un miembro de 'basic_ostream'. Aceptar, por lo que el operador << regresa ostream en lugar de ostringstream -? ¿Qué hay de fundición de nuevo a un ostringstream

1) ¿Es este reparto seguro?

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

Ahora, con esto, resulta que para el operador << ( "Valor:") llamada, se trata en realidad de llamar ostream operador << (void *) e imprimir una dirección hexadecimal. Esto está mal, quiero que el texto.

2) ¿Por qué operador << en la std :: temporal ostringstream () llamar al operador ostream? Sin duda, el temporal tiene un tipo de 'ostringstream' no 'ostream'?

puedo emitir el temporal para forzar la llamada del operador correcto también!

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

Esto parece trabajar y pasa "Valor: 5" para f ()

.

3) ¿Estoy confiando en un comportamiento indefinido ahora? Los moldes se ven inusual.


Soy consciente de la mejor alternativa es algo como esto:

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

... pero estoy interesado en el comportamiento de hacerlo en una sola línea. Supongamos que alguien quería hacer una (dudosa) 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));
¿Sería esta función como se esperaba

¿Fue útil?

Solución

No se puede emitir el flujo temporal a std::ostringstream&. Se formó-enfermo (el compilador debe decirle que es un error). Lo siguiente puede hacerlo, sin embargo:

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

Eso por supuesto es feo. Pero muestra cómo se puede trabajar. seekp es una función miembro de devolver un std::ostream&. Probablemente mejor escribir esto generalmente

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 razón de que sin nada que tarda el void*, se debe a que operator<< es una función miembro. El operator<< que toma un char const* no lo es.

Otros consejos

Un temporal no se pueden pasar como una referencia no const a una función, es por eso que no encuentra el operador de streaming correcta y en su lugar toma el uno con void * argumento (que es una función miembro y por lo tanto llamándolo de forma temporal está bien).

Lo que viene a moverse por las limitaciones por fundición, tengo la sensación de que se trata, de hecho, UB, pero no puedo decir con seguridad. Otra persona seguramente citar la norma.

Esto se puede hacer usando una función lambda C ++ 11.

#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 te gusta declaraciones one_lined puede escribir:

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

Sin embargo se debe preferir más fácil de mantener código como:

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

utilizo algo un poco como esta para el registro.

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

Salida:

Mi primer mensaje

Otro mensaje

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top