c++iomanip

is there a good way to combine stream manipulators?


If I wanted to output a fixed width hex number with 4 digits on a stream, I would need to do something like this:

cout << "0x" << hex << setw(4) << setfill('0') << 0xABC;

which seems a bit long winded. Using a macro helps:

#define HEX(n) "0x" << hex << setw(n) << setfill('0')

cout << HEX(4) << 0xABC;

Is there a better way to combine the manipulators?


Solution

  • Avoid the macros when you can! They hide code, making things hard to debug, don't respect scope, etc.

    You can use a simple function as KenE provided. If you want to get all fancy and flexible, then you can write your own manipulator:

    #include <iostream>
    #include <iomanip>
    using namespace std;
    
    ostream& hex4(ostream& out)
    {
        return out << "0x" << hex << setw(4) << setfill('0');
    }
    
    int main()
    {
        cout << hex4 << 123 << endl;
    }
    

    This makes it a little more general. The reason the function above can be used is because operator<< is already overloaded like this: ostream& operator<<(ostream&, ostream& (*funtion_ptr)(ostream&)). endl and some other manipulators are also implemented like this.

    If you want to allow the number of digits to be specified at runtime, we can use a class:

    #include <iostream>
    #include <iomanip>
    using namespace std;
    
    struct formatted_hex
    {
        unsigned int n;
        explicit formatted_hex(unsigned int in): n(in) {}
    };
    
    ostream& operator<<(ostream& out, const formatted_hex& fh)
    {
        return out << "0x" << hex << setw(fh.n) << setfill('0');
    }
    
    int main()
    {
        cout << formatted_hex(4) << 123 << endl;
    }
    

    If the size can be determined at compile-time, however, might as well just use a function template [thanks to Jon Purdy for this suggestion]:

    template <unsigned int N>
    ostream& formatted_hex(ostream& out)
    {
        return out << "0x" << hex << setw(N) << setfill('0');
    }
    
    int main()
    {
        cout << formatted_hex<4> << 123 << endl;
    }