tags:

views:

66

answers:

4

Hi

Is there are a better way than this one to print 2d table?

  std::cout 
      << std::setw(25) << left << "FF.name"
      << std::setw(25) << left << "BB.name"
      << std::setw(12) << left << "sw.cycles"
      << std::setw(12) << left << "hw.cycles"  << "\n"
      << std::setw(25) << left << "------"
      << std::setw(25) << left << "------"
      << std::setw(12) << left << "---------"
      << std::setw(12) << left << "---------"  << "\n";
A: 

Use printf. It's part of C, but it's still supported in C++.

Simon Nickerson
or even #define
slf
I did that before. The code and result looks good. The thing however is to do that in C++.
name
it's a bad idea to mix `printf` with `cout <<`
Inverse
@Inverse: Only if you call std::ios_base::sync_with_stdio(false) (it defaults to true).
Roger Pate
+2  A: 

You could put the headers into an array or vector, then generate the correct widths automatically:

boost::array<std::string, 4> head = { ... }

BOOST_FOREACH(std::string& s, head)
{
    int w = 5*(s.length()/5 + 1);
    std::cout << std::setw(w) << left << s;
}
std::cout << '\n';

BOOST_FOREACH(std::string& s, head)
{
    int w = 5*(s.length()/5 + 1);
    std::cout << std::string(w,'-');
}
std::cout << std::endl;

Might be worthwhile if you have lots of headers I guess.

Inverse
+1: Auto-generation of the widths is a nice touch.
Troubadour
A: 

Break things up into functions and it's not so bad.

#include <iostream>
#include <iomanip>
#include <string>
#include <vector>

typedef std::vector< std::string > StringVector;


void printRow( std::ostream& s, const StringVector& strings )
{
    s << std::setw(25) << std::left << strings[ 0 ];
    s << std::setw(25) << std::left << strings[ 1 ];
    s << std::setw(12) << std::left << strings[ 2 ];
    s << std::setw(12) << std::left << strings[ 3 ];
    s << "\n";
}

void printHeadings( std::ostream& s, const StringVector& headings )
{
    printRow( s, headings );
    StringVector lines;
    for ( StringVector::const_iterator H  = headings.begin();
                                       H != headings.end();
                                     ++H )
    {
        lines.push_back( std::string( H->size(), '-' ) );
    }
    printRow( s, lines );
}

int main()
{
    StringVector headings( 4 );
    headings[ 0 ] = "FF.name";
    headings[ 1 ] = "BB.name";
    headings[ 2 ] = "sw.cycles";
    headings[ 3 ] = "hw.cycles";

    printHeadings( std::cout, headings );

    StringVector contents( 4 );
    contents[ 0 ] = "foo";
    contents[ 1 ] = "bar";
    contents[ 2 ] = "baz";
    contents[ 3 ] = "foobarbaz";
    printRow( std::cout, contents );

    return 0;
}

Note that I've left out the bounds checking on the string vectors since this is only intended as an example.

Troubadour
for sure it's readable but it's also a lot of code just to print the table.
name
A: 

Width is the only formatting setting that gets reset, so you can trivially simplify to:

std::cout << left;
std::cout
  << std::setw(25) << "FF.name"
  << std::setw(25) << "BB.name"
  << std::setw(12) << "sw.cycles"
  << std::setw(12) << "hw.cycles"
  << "\n";

You might like:

//...
std::cout << w(25, "FF.name");
//...

// implemented:

template<class T>
struct AtWidth {
  std::streamsize width;
  T const& obj;
  AtWidth(std::streamsize width, T const& obj) : width(width), obj(obj) {}
  template<class Stream> // easier than templating on basic_stream
  friend Stream& operator<<(Stream& s, AtWidth const& value) {
    s.width(value.width);
    return s << value.obj;
  }
};

template<class T>
AtWidth<T> w(std::streamsize width, T const& obj) {
  return AtWidth<T>(width, obj);
}

Or if you want to rename the setw function (C++0x):

auto w(std::streamsize width) -> decltype(std::setw(width)) {
  return std::setw(width);
}
// ...
std::cout << w(25) << "FF.name";

(In non-0x, you'd have to either know how your library implements setw to get the right type or re-write it yourself, which isn't too hard, BTW.)

Edit: I missed the second line of dashes here, another answer covers that well enough. The solution for that is indeed to construct a header "object" and print it out more or less at once.

Roger Pate