c++c++11code-duplicationiomanip

How to print a bunch of integers with the same formatting?


I would like to print a bunch of integers on 2 fields with '0' as fill character. I can do it but it leads to code duplication. How should I change the code so that the code duplication can be factored out?

#include <ctime>
#include <sstream>
#include <iomanip>
#include <iostream>

using namespace std;

string timestamp() {

    time_t now = time(0);

    tm t = *localtime(&now);

    ostringstream ss;

    t.tm_mday = 9; // cheat a little to test it
    t.tm_hour = 8;

    ss << (t.tm_year+1900)
       << setw(2) << setfill('0') << (t.tm_mon+1) // Code duplication
       << setw(2) << setfill('0') <<  t.tm_mday
       << setw(2) << setfill('0') <<  t.tm_hour
       << setw(2) << setfill('0') <<  t.tm_min
       << setw(2) << setfill('0') <<  t.tm_sec;

    return ss.str();
}

int main() {

    cout << timestamp() << endl;

    return 0;
}

I have tried

std::ostream& operator<<(std::ostream& s, int i) {

    return s << std::setw(2) << std::setfill('0') << i;
}

but it did not work, the operator<< calls are ambigous.


EDIT I got 4 awesome answers and I picked the one that is perhaps the simplest and the most generic one (that is, doesn't assume that we are dealing with timestamps). For the actual problem, I will probably use std::put_time or strftime though.


Solution

  • You need a proxy for your string stream like this:

    struct stream{
        std::ostringstream ss;
        stream& operator<<(int i){
            ss << std::setw(2) << std::setfill('0') << i;
            return *this; // See Note below
        }
    }; 
    

    Then your formatting code will just be this:

    stream ss;
    ss << (t.tm_year+1900)
       << (t.tm_mon+1)
       << t.tm_mday
       << t.tm_hour
       << t.tm_min
       << t.tm_sec;
    
    return ss.ss.str();
    

    ps. Note the general format of my stream::operator<<() which does its work first, then returns something.