Restaure el estado de std :: cout después de manipularlo

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 manera de ‘restaurar’ el estado de cout a su original después de regresar de la función? (Algo así como std :: boolalpha y std :: noboolalpha ..)?

Gracias.

necesita #include o #include luego cuando sea necesario:

 std::ios_base::fmtflags f( cout.flags() ); //Your code here... cout.flags( f ); 

Podrías ponerlos al principio y al final de tu función, o ver esta respuesta sobre cómo usar esto con RAII .

El Boost IO Stream State Saver parece exactamente lo que necesita. 🙂

Ejemplo basado en tu fragmento de código:

 void printHex(std::ostream& x) { boost::io::ios_flags_saver ifs(x); x < < std::hex << 123; } 

Tenga en cuenta que las respuestas presentadas aquí no restaurarán el estado completo de std::cout . Por ejemplo, std::setfill se “pegará” 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 

Creé 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 indicadores en un iostream. Cualquiera que sea la ruta de retorno utilizada, siempre se llamará al destructor y las banderas siempre se restablecerán. No hay ninguna posibilidad de olvidar restaurar las banderas cuando la función vuelve.

 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 siempre que desee guardar el estado del indicador actual. Cuando esta instancia se sale del scope, se restaurará el estado de la bandera.

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

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.. } 

Puede crear otro contenedor alrededor del buffer stdout:

 #include  #include  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 caro 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 consistente y usar .setf() también en lugar de la < < syntax (pregunta pura 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 otros han dicho, puedes poner lo anterior (y .precision() y .fill() , pero normalmente no la configuración regional y las palabras relacionadas que normalmente no se van a modificar y son más pesadas) en una clase por conveniencia y para hacerla a prueba de excepciones; el constructor debería aceptar std::ios& .