printing 2d table (headers)
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";
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.
Use printf. It's part of C, but it's still supported in C++.
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.
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.
精彩评论