Pregunta

Estoy creando un registrador con las siguientes secciones:

// #define LOG(x) // for release mode
#define LOG(x) log(x)

log(const string& str);
log(const ostream& str);

Con la idea de hacer:

LOG("Test");
LOG(string("Testing") + " 123");
stringstream s;
LOG(s << "Testing" << 1 << "two" << 3);

Todo esto funciona como se pretende, pero cuando lo hago:

LOG(stringstream() << "Testing" << 1 << "two" << 3);

No funciona:

void log(const ostream& os)
{
  std::streambuf* buf = os.rdbuf();
  if( buf && typeid(*buf) == typeid(std::stringbuf) )
  {
    const std::string& format = dynamic_cast<std::stringbuf&>(*buf).str();
    cout << format << endl;
  }
}

resultados en 'formato' que contiene datos no deseados en lugar de la habitual cadena correcta.

Creo que esto es debido a que el ostream temporal devuelto por el operador << sobrevive al stringstream viene.

O estoy equivocado?

(¿Por qué sarta de trabajo () de esta manera? ¿Es porque se devuelve una referencia a sí mismo? Asumo que sí.)

Me gustaría mucho hacerlo de esta manera ya que sería la eliminación de una asignación adicional al iniciar la sesión en modo de lanzamiento.

Cualquier indicador o trucos para lograr que se haga de esta manera serían bien recibidos. En mi solución real que tengo muchas funciones diferentes de registro y todos son más complejo que esto. Así que yo preferiría tener esta implementado alguna manera en el código de llamada. (Y no mediante la modificación de mi # define si es posible)

Sólo para dar una idea, un ejemplo de uno de mis #defines reales:

#define LOG_DEBUG_MSG(format, ...) \
  LogMessage(DEBUG_TYPE, const char* filepos, sizeof( __QUOTE__( @__VA_ARGS__ )), \
  format, __VA_ARGS__)

que coincide varargs funciones printf-como de registro teniendo char *, secuencia () y ostream (), así como funciones no vararg teniendo string (), excepción () y HRESULT.

¿Fue útil?

Solución

piensan que ver lo que está pasando. Esto produce el resultado esperado:

log(std::stringstream() << 1 << "hello");

Si bien esto no es así:

log(std::stringstream() << "hello" << 1);

(se escribe un número hexadecimal, seguido por el dígito "1")

Unos elementos para la explicación:

  • Un valor p no puede estar unido a una referencia no const
  • Está bien para invocar funciones miembro de forma temporal
  • std :: ostream tiene un miembro de operador << (void *)
  • std :: ostream tiene un miembro de operador << (int)
  • Para char * el operador no es miembro, se operador << (std :: ostream y, const char *)

En el código anterior, std :: stringstream () crea un temporal (un valor de lado derecho). Su vida no es problemático, ya que debe durar toda la expresión completa se declara en (es decir, hasta que la llamada a log () devoluciones).

En el primer ejemplo, todo funciona bien porque el operador miembro de << (int) se llama en primer lugar, y luego la referencia devuelta se puede pasar a operador << (ostream y, const char *)

En el segundo ejemplo, el operador << (no puede ser llamado con "std :: stringstream ()" como una primera discusión, ya que esto requeriría que se una a una referencia no const. Sin embargo, el operador miembro < <(void *) está bien, ya que es un miembro.

Por cierto: ¿Por qué no definir la función log () como:

void log(const std::ostream& os)
{
    std::cout << os.rdbuf() << std::endl;
}

Otros consejos

Alterar su macro LOG() a esto:

#define LOG(x) do { std::stringstream s; s << x; log(s.str()); } while(0)

Esto le permitirá utilizar la siguiente sintaxis en los registros de depuración, por lo que no tiene que construir manualmente la corriente de cadena.

LOG("Testing" << 1 << "two" << 3);

A continuación, defina a la nada de la liberación, y usted no tiene asignaciones adicionales.

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