Restaurer l’état de std :: cout après l’avoir manipulé

Supposons que j’ai un code comme celui-ci:

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

Ma question est la suivante: existe-t-il un moyen de «restaurer» l’état de cout après son retour de la fonction? (Un peu comme std :: boolalpha et std :: noboolalpha ..)?

Merci.

vous devez #include ou #include alors, si nécessaire:

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

Vous pouvez les mettre au début et à la fin de votre fonction, ou consulter cette réponse pour savoir comment l’utiliser avec RAII .

Le Boost IO Stream State Saver semble exactement ce dont vous avez besoin. 🙂

Exemple basé sur votre extrait de code:

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

Notez que les réponses présentées ici ne restaureront pas l’état complet de std::cout . Par exemple, std::setfill “collera” même après avoir appelé .flags() . Une meilleure solution consiste à utiliser .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; 

Imprimera:

 case closed 

plutôt que:

 case closed0000 

J’ai créé une classe RAII en utilisant l’exemple de code de cette réponse. Le gros avantage de cette technique réside dans le fait que vous avez plusieurs chemins de retour depuis une fonction qui définit des indicateurs sur un stream iostream. Quel que soit le chemin de retour utilisé, le destructeur sera toujours appelé et les drapeaux seront toujours réinitialisés. Il n’y a aucune chance d’oublier de restaurer les drapeaux lorsque la fonction revient.

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

Vous l’utiliserez ensuite en créant une instance locale de IosFlagSaver chaque fois que vous souhaitez enregistrer l’état d’indicateur actuel. Lorsque cette instance est hors de scope, l’état du pavillon sera restauré.

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

Avec un peu de modification pour rendre la sortie plus lisible:

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

Vous pouvez créer un autre wrapper autour du tampon 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" } 

Dans une fonction:

 void print(std::ostream& os) { std::ostream copy (os.rdbuf()); copy << std::hex; copy << 123; } 

Bien sûr, si les performances posent problème, cela coûte un peu plus cher car cela consiste à copier tout l’object ios (mais pas le tampon), y compris certains éléments que vous payez mais qu’il est peu probable d’utiliser, tels que les parameters régionaux.

Sinon, je pense que si vous utilisez .flags() il vaut mieux être cohérent et utiliser aussi .setf() plutôt que la syntaxe << (pure question de style).

 void print(std::ostream& os) { std::ios::fmtflags os_flags (os.flags()); os.setf(std::ios::hex); os << 123; os.flags(os_flags); } 

Comme d’autres l’ont dit, vous pouvez mettre les éléments ci-dessus (et .precision() et .fill() , mais généralement pas les parameters régionaux et les mots associés qui ne seront généralement pas modifiés et sont plus lourds) dans une classe. faites-le en toute sécurité le constructeur doit accepter std::ios& .