c++ - such - iostream vs stdio
Restaura el estado de std:: cout después de manipularlo (6)
Supongamos que tengo un código como este:
void printHex(std::ostream& x){
x<<std::hex<<123;
}
..
int main(){
std::cout<<100; // prints 100 base 10
printHex(std::cout); //prints 123 in hex
std::cout<<73; //problem! prints 73 in hex..
}
Mi pregunta es si hay alguna forma de "restaurar" el estado de cout a su estado original después de regresar de la función. (Algo así como std :: boolalpha y std :: noboolalpha ..)?
Gracias.
Con un poco de modificación para que la salida sea más legible:
void printHex(std::ostream& x) {
ios::fmtflags f(x.flags());
x << std::hex << 123 << "/n";
x.flags(f);
}
int main() {
std::cout << 100 << "/n"; // prints 100 base 10
printHex(std::cout); // prints 123 in hex
std::cout << 73 << "/n"; // problem! prints 73 in hex..
}
He creado una clase RAII usando el código de ejemplo de esta respuesta. La gran ventaja de esta técnica viene si tiene varias rutas de retorno desde una función que establece banderas en un iostream. Cualquiera que sea la ruta de retorno que se use, siempre se llamará al destructor y las banderas siempre se restablecerán. No hay posibilidad de olvidar restaurar las banderas cuando la función regresa.
class IosFlagSaver {
public:
explicit IosFlagSaver(std::ostream& _ios):
ios(_ios),
f(_ios.flags()) {
}
~IosFlagSaver() {
ios.flags(f);
}
IosFlagSaver(const IosFlagSaver &rhs) = delete;
IosFlagSaver& operator= (const IosFlagSaver& rhs) = delete;
private:
std::ostream& ios;
std::ios::fmtflags f;
};
Luego lo usaría creando una instancia local de IosFlagSaver cuando quisiera guardar el estado de marca actual. Cuando esta instancia queda fuera del alcance, el estado del indicador será restaurado.
void f(int i) {
IosFlagSaver iosfs(std::cout);
std::cout << i << " " << std::hex << i << " ";
if (i < 100) {
std::cout << std::endl;
return;
}
std::cout << std::oct << i << std::endl;
}
Puedes crear otro envoltorio alrededor del búfer stdout:
#include <iostream>
#include <iomanip>
int main() {
int x = 76;
std::ostream hexcout (std::cout.rdbuf());
hexcout << std::hex;
std::cout << x << "/n"; // still "76"
hexcout << x << "/n"; // "4c"
}
En una función:
void print(std::ostream& os) {
std::ostream copy (os.rdbuf());
copy << std::hex;
copy << 123;
}
Por supuesto, si el rendimiento es un problema, es un poco más costoso porque está copiando todo el objeto ios
(pero no el búfer), incluidas algunas cosas que está pagando pero que es poco probable que use, como la configuración regional.
De lo contrario, siento que si vas a usar .flags()
es mejor ser coherente y usar .setf()
también en lugar de la sintaxis <<
(pura cuestión de estilo).
void print(std::ostream& os) {
std::ios::fmtflags os_flags (os.flags());
os.setf(std::ios::hex);
os << 123;
os.flags(os_flags);
}
Como han dicho otros, puede colocar lo anterior (y .precision()
y .fill()
, pero generalmente no la configuración regional y las cosas relacionadas con las palabras que normalmente no se van a modificar y que son más pesadas) en una clase por conveniencia y para hacer que la excepción sea segura; el constructor debe aceptar std::ios&
.
Tenga en cuenta que las respuestas que se presentan aquí no restaurarán el estado completo de std::cout
. Por ejemplo, std::setfill
se "mantendrá" incluso después de llamar a .flags()
. Una mejor solución es usar .copyfmt
:
std::ios oldState(nullptr);
oldState.copyfmt(std::cout);
std::cout
<< std::hex
<< std::setw(8)
<< std::setfill(''0'')
<< 0xDECEA5ED
<< std::endl;
std::cout.copyfmt(oldState);
std::cout
<< std::setw(15)
<< std::left
<< "case closed"
<< std::endl;
Se imprimirá:
case closed
más bien que:
case closed0000
necesita #include <iostream>
o #include <ios>
luego, cuando sea necesario:
std::ios_base::fmtflags f( cout.flags() );
//Your code here...
cout.flags( f );
Puede poner esto al principio y al final de su función, o verifique esta respuesta sobre cómo usar esto con RAII .
Boost IO Stream State Saver parece exactamente lo que necesitas. :-)
Ejemplo basado en su fragmento de código:
void printHex(std::ostream& x) {
boost::io::ios_flags_saver ifs(x);
x << std::hex << 123;
}