Restore the state of std::cout after manipulating it

Viewed 54251

Suppose I have a code like this:

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

My question is if there is any way to 'restore' the state of cout to its original one after returning from the function? (Somewhat like std::boolalpha and std::noboolalpha..) ?

Thanks.

9 Answers

you need to #include <iostream> or #include <ios> then when required:

std::ios_base::fmtflags f( cout.flags() );

//Your code here...

cout.flags( f );

You can put these at the beginning and end of your function, or check out this answer on how to use this with RAII.

The Boost IO Stream State Saver seems exactly what you need. :-)

Example based on your code snippet:

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

With a little bit of modification to make the output more readable :

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

C++20 std::format will be a superior alternative to save restore in most cases

Once you can use it, you will e.g. be able to write hexadecimals simply as:

#include <format>
#include <string>

int main() {
    std::cout << std::format("{:x} {:#x} {}\n", 16, 17, 18);
}

Expected output:

10 0x11 18

This will therefore completely overcome the madness of modifying std::cout state.

The existing fmt library implements it for before it gets official support: https://github.com/fmtlib/fmt Install on Ubuntu 22.04:

sudo apt install libfmt-dev

Modify source to replace:

  • <format> with <fmt/core.h>
  • std::format to fmt::format

main.cpp

#include <iostream>

#include <fmt/core.h>

int main() {
    std::cout << fmt::format("{:x} {:#x} {}\n", 16, 17, 18);
}

and compile and run with:

g++ -std=c++11 -o main.out main.cpp -lfmt
./main.out

Output:

10 0x11 18

Related: std::string formatting like sprintf

I would like to generalize the answer from qbert220 somewhat:

#include <ios>

class IoStreamFlagsRestorer
{
public:
    IoStreamFlagsRestorer(std::ios_base & ioStream)
        : ioStream_(ioStream)
        , flags_(ioStream_.flags())
    {
    }

    ~IoStreamFlagsRestorer()
    {
        ioStream_.flags(flags_);
    }

private:
    std::ios_base & ioStream_;
    std::ios_base::fmtflags const flags_;
};

This should work for input streams and others as well.

PS: I would have liked to make this simply a comment to above answer, stackoverflow however does not allow me to do so because of missing reputation. Thus make me clutter the answers here instead of a simple comment...

Instead of injecting format into cout, the << way, adopting setf and unsetf could be a cleaner solution.

void printHex(std::ostream& x){
  x.setf(std::ios::hex, std::ios::basefield);
  x << 123;
  x.unsetf(std::ios::basefield);
}

the ios_base namespace works fine too

void printHex(std::ostream& x){
  x.setf(std::ios_base::hex, std::ios_base::basefield);
  x << 123;
  x.unsetf(std::ios_base::basefield);
}

Reference: http://www.cplusplus.com/reference/ios/ios_base/setf/

Related