Search code examples
c++unicodecoutwindows-consolesetw

How to format text using std:out setfill std::setw std:right with one padding space


I just want to format a string and an integer value with right justify. There is no problem to do this without leading space before the integer value.

bytes.....................123981
total bytes..............1030131 

But it should look like this:

bytes ................... 123981
total bytes ............ 1030131

Unfortunately the example below wont work, because setw (right justify) relates only to the next stream element.

int iBytes = 123981;
int iTotalBytes = 1030131;
cout << setfill('.');
cout << right;
cout << "bytes " << setw(20) << " " << iBytes << endl;
cout << "total bytes " << setw(14) << " " << iTotalBytes << endl;

I hardly ever use std::cout, so is there a simple way to do this without previously joining a space char to the value?


Solution

  • The simplest way would be to write your " " and value into a std::stringstream and write the resulting str() into your output stream like:

    std::stringstream ss;
    ss << " " << iBytes;
    cout << "bytes " << setw(20) << ss.str() << endl;
    

    And here comes the complete overkill. A templated class prefixed which can be printed and bundles the two constructor arguments prefix,val into one string to be printed. number format, and precision is taken from the final output stream. Works with ints,floats, strings and const char *. And should work with every arg that has a valid output operator.

    #include <fstream> 
    #include <iostream> 
    #include <iomanip> 
    #include <sstream> 
    
    using  namespace std; 
    
    template<class T> 
    class prefixed_base  { 
    public: 
        prefixed_base(const std::string & prefix,const T val) : _p(prefix),_t(val) { 
        } 
    protected: 
        std::string _p; 
        T           _t; 
    }; 
    
    // Specialization for const char *
    template<> 
    class prefixed_base<const char*>  { 
    public: 
        prefixed_base(const std::string & prefix,const char * val) : _p(prefix),_t(val) { 
        } 
    protected: 
        std::string _p; 
        std::string _t; 
    }; 
    
    template<class T> 
    class prefixed : public  prefixed_base<T> { 
    private: 
        typedef prefixed_base<T> super; 
    public: 
        prefixed(const std::string & prefix,const T val) : super(prefix,val) { 
        } 
    
        // Output the prefixed value to an ostream
        // Write into a stringstream and copy most of the
        // formats from os.
    
        std::ostream & operator()(std::ostream & os) const { 
            std::stringstream ss; 
    
            // We 'inherit' all formats from the 
            // target stream except with. This Way we 
            // keep informations like hex,dec,fixed,precision 
    
            ss.copyfmt(os); 
            ss << std::setw(0); 
            ss << super::_p; 
    
            ss.copyfmt(os); 
            ss << std::setw(0); 
            ss << super::_t; 
    
            return os << ss.str(); 
        } 
    }; 
    
    // Output operator for class prefixed
    template<class T> 
    std::ostream & operator<<(std::ostream & os,const prefixed<T> & p) { 
        return p(os); 
    } 
    
    // This function can be used directly for output like os << with_prefix(" ",33.3)
    template<class T> 
    prefixed<T>    with_prefix(const std::string & p,const T  v) { 
        return prefixed<T>(p,v); 
    } 
    
    int main() { 
        int iBytes = 123981; 
        int iTotalBytes = 1030131; 
        cout << setfill('.'); 
        cout << right; 
    
        cout << "bytes " << setw(20) << with_prefix(" ",iBytes) << endl; 
        cout << "total bytes " << setw(14) << with_prefix(" ",iTotalBytes) << endl; 
    
        cout << "bla#1 "       << setw(20) <<  std::fixed << std::setprecision(9) << with_prefix(" ",220.55)      << endl; 
        cout << "blablabla#2 " << setw(14) <<  std::hex << with_prefix(" ",iTotalBytes) << endl; 
    }