c++ - tratarlos - manipulador emocional pareja
"Roll-Back" o deshacer cualquier manipulador aplicado a una corriente sin saber qué eran los manipuladores (5)
Si aplico una cantidad arbitraria de manipuladores a una secuencia, ¿hay alguna manera de deshacer la aplicación de esos manipuladores de forma genérica?
Por ejemplo, considere lo siguiente:
#include <iostream>
#include <iomanip>
using namespace std;
int main()
{
cout << "Hello" << hex << 42 << "/n";
// now i want to "roll-back" cout to whatever state it was in
// before the code above, *without* having to know
// what modifiers I added to it
// ... MAGIC HAPPENS! ...
cout << "This should not be in hex: " << 42 << "/n";
}
Supongamos que quiero agregar un código en MAGIC HAPPENS
que revertirá el estado de los manipuladores de flujo a lo que sea antes de hacerlo cout << hex
. Pero no sé qué manipuladores agregué. ¿Cómo puedo lograr esto?
En otras palabras, me gustaría poder escribir algo como esto (código de psudocódigo / fantasía):
std::something old_state = cout.current_manip_state();
cout << hex;
cout.restore_manip_state(old_state);
es posible?
EDITAR:
En caso de que tenga curiosidad, estoy interesado en hacer esto en un operator<<()
personalizado operator<<()
Estoy escribiendo para un tipo complejo. El tipo es un tipo de unión discriminada, y los diferentes tipos de valores tendrán diferentes manips aplicados a la transmisión.
EDIT2:
Restricción: No puedo usar Boost ni ninguna otra biblioteca de terceros. La solución debe estar en C ++ estándar.
Boost IO State Saver puede ser de ayuda.
http://www.boost.org/doc/libs/1_40_0/libs/io/doc/ios_state.html
Guardar y restaurar el estado no es una excepción. Yo propondría mezclar todo en una stringstream
, y finalmente poner eso en la corriente real (que nunca ha cambiado sus banderas).
#include <iostream>
#include <iomanip>
#include <sstream>
int main()
{
std::ostringstream out;
out << "Hello" << std::hex << 42 << "/n";
std::cout << out.str();
// no magic necessary!
std::cout << "This should not be in hex: " << 42 << "/n";
}
Por supuesto, esto es un poco menos eficiente. Las soluciones perfectas dependen de sus necesidades específicas.
Los manipuladores estándar manipulan banderas de formato de una secuencia, ajustes de precisión y ancho. La configuración de ancho se reinicia por la mayoría de las operaciones de salida formateadas de todos modos. Todos estos se pueden recuperar de esta manera:
std::ios_base::fmtflags saveflags = std::cout.flags();
std::streamsize prec = std::cout.precision();
std::streamsize width = std::cout.width();
y restaurado:
std::cout.flags( saveflags );
std::cout.precision( prec );
std::cout.width( width );
Convertir esto en una clase RAII es un ejercicio para el lector ...
Sé que es una vieja pregunta, pero para las generaciones futuras:
También puede escribir un protector de estado simple usted mismo (sin duda le ayudará a evitar que se cambie el estado). Simplemente use la solución sugerida por @loki y ejecútela desde el constructor / destructor de un objeto (en resumen: RAII) en esta línea:
class stateSaver
{
public:
stateSaver(ostream& os): stream_(os), state_(nullptr) { state_.copyfmt(os); }
~stateSaver() { stream_.copyfmt(state_); }
private:
std::ios state_;
ostream& stream_;
};
Entonces, lo usarás así:
void myFunc() {
stateSaver state(cout);
cout << hex << 42 << endl; // will be in hex
}
int main() {
cout << 42 << endl; // will be in dec
myFunc();
cout << 42 << endl; // will also be in dec
}
Sí.
Puede guardar el estado y restaurarlo:
#include <iostream>
#include <iomanip>
using namespace std;
int main()
{
std::ios state(NULL);
state.copyfmt(std::cout);
cout << "Hello" << hex << 42 << "/n";
// now i want to "roll-back" cout to whatever state it was in
// before the code above, *without* having to know what modifiers I added to it
// ... MAGIC HAPPENS! ...
std::cout.copyfmt(state);
cout << "This should not be in hex: " << 42 << "/n";
}
Si desea volver al estado predeterminado, ni siquiera necesita guardar el estado, puede extraerlo de un objeto temporal.
std::cout.copyfmt(std::ios(NULL));