c++ - how - instagram hashtags in comments
Manejo de sobrecarga de std:: endl? (6)
De acuerdo con Neil por principio.
Desea cambiar el comportamiento del búfer, porque esa es la única forma de extender iostreams. endl
hace esto:
flush(__os.put(__os.widen(''/n'')));
widen
devuelve un solo carácter, por lo que no puede poner su cadena allí. put
llamadas putc
que no es una función virtual y solo ocasionalmente se engancha al overflow
. Puede interceptar en flush
, que llama a la sync
del búfer. Debería interceptar y cambiar todos los caracteres de nueva línea a medida que se overflow
o se sync
manualmente y los convierta en su cadena.
Diseñar una clase de almacenamiento intermedio de sustitución es problemático porque basic_streambuf
espera acceso directo a su memoria intermedia. Esto le impide pasar fácilmente las solicitudes de E / S a un basic_streambuf
preexistente. Necesita salir de una extremidad y suponga que conoce la clase de buffer de transmisión y derivar de ella. ( cin
y cout
no tienen garantizado el uso de basic_filebuf
, por lo que yo sé). Luego, simplemente agregue virtual overflow
y la sync
. (Ver §27.5.2.4.5 / 3 y 27.5.2.4.2 / 7.) Realizar la sustitución puede requerir espacio adicional, así que tenga cuidado de asignarlo con anticipación.
- O -
¡Solo declara un nuevo endl
en tu propio espacio de nombres, o mejor, un manipulador que no se llama endl
para nada!
Quiero definir una clase MyStream
para que:
MyStream myStream;
myStream << 1 << 2 << 3 << std::endl << 5 << 6 << std::endl << 7 << 8 << std::endl;
da salida
[blah]123
[blah]56
[blah]78
Básicamente, quiero un "[blah]" insertado en la parte delantera, luego insertada después de cada std::endl
no terminante ?
La dificultad aquí NO es la gestión lógica, sino la detección y sobrecarga del manejo de std::endl
. ¿Hay una manera elegante de hacer esto?
¡Gracias!
EDITAR: No necesito consejos sobre gestión lógica. Necesito saber cómo detectar / sobrecargar la impresión de std::endl
.
En lugar de intentar modificar el comportamiento de std::endl
, probablemente debería crear un streambuf de filtrado para hacer el trabajo. James Kanze tiene un example muestra cómo insertar una marca de tiempo al comienzo de cada línea de salida. Debería requerir solo modificaciones menores para cambiar eso al prefijo que desee en cada línea.
Lo que debes hacer es escribir tu propio buffer de transmisión:
Cuando se descarga el búfer de transmisión, se imprime el prefijo de los caracteres y el contenido de la secuencia.
El siguiente funciona porque std :: endl causa lo siguiente.
1) Agregue ''/ n'' a la transmisión.
2) Llama a flush () en la transmisión
2a) Esto llama a pubsync () en el buffer de la secuencia.
2b) Esto llama al método virtual sync ()
2c) Reemplazar este método virtual para hacer el trabajo que desee.
#include <iostream>
#include <sstream>
class MyStream: public std::ostream
{
// Write a stream buffer that prefixes each line with Plop
class MyStreamBuf: public std::stringbuf
{
std::ostream& output;
public:
MyStreamBuf(std::ostream& str)
:output(str)
{}
~MyStreamBuf() {
if (pbase() != pptr()) {
putOutput();
}
}
// When we sync the stream with the output.
// 1) Output Plop then the buffer
// 2) Reset the buffer
// 3) flush the actual output stream we are using.
virtual int sync() {
putOutput();
return 0;
}
void putOutput() {
// Called by destructor.
// destructor can not call virtual methods.
output << "[blah]" << str();
str("");
output.flush();
}
};
// My Stream just uses a version of my special buffer
MyStreamBuf buffer;
public:
MyStream(std::ostream& str)
:std::ostream(&buffer)
,buffer(str)
{
}
};
int main()
{
MyStream myStream(std::cout);
myStream << 1 << 2 << 3 << std::endl << 5 << 6 << std::endl << 7 << 8 << std::endl;
}
> ./a.out
[blah]123
[blah]56
[blah]78
>
No puede cambiar std::endl
, ya que su nombre sugiere que forma parte de la biblioteca estándar de C ++ y su comportamiento es fijo. Debe cambiar el comportamiento de la transmisión en sí, cuando recibe un final de línea. Personalmente, no hubiera creído que valiera la pena el esfuerzo, pero si desea incursionar en esta área, le recomiendo leer el libro Standard C ++ IOStreams & Locales .
Sus operadores sobrecargados de la clase MyStream
tienen que establecer un indicador previo-impreso-token-era-endl.
Luego, si se imprime el siguiente objeto, se puede insertar [blah]
delante de él.
std::endl
es una función que toma y devuelve una referencia a std::ostream
. Para detectar que se cambió a su transmisión, debe sobrecargar el operator<<
entre su tipo y dicha función:
MyStream& operator<<( std::ostream&(*f)(std::ostream&) )
{
std::cout << f;
if( f == std::endl )
{
_lastTokenWasEndl = true;
}
return *this;
}
Yo uso punteros de función. Suena aterrador para las personas que no están acostumbradas a C, pero es mucho más eficiente en la mayoría de los casos. Aquí hay un ejemplo:
#include <iostream>
class Foo
{
public:
Foo& operator<<(const char* str) { std::cout << str; return *this; }
// If your compiler allows it, you can omit the "fun" from *fun below. It''ll make it an anonymous parameter, though...
Foo& operator<<(std::ostream& (*fun)(std::ostream&)) { std::cout << std::endl; }
} foo;
int main(int argc,char **argv)
{
foo << "This is a test!" << std::endl;
return 0;
}
Si realmente lo deseas, puedes verificar la dirección de endl para confirmar que no obtienes alguna OTRA función vacía / nula, pero no creo que valga la pena en la mayoría de los casos. Espero que eso ayude.