std::string是个很不错的东东,但实际使用时基本在每个程序里都会遇到不愉快的事情:格式化字符串。我甚至由于这个原因在代码里引入平台有关的MFC,ATL等本来不需要在项目中使用的一些重量级的框架,就为了能轻松的做格式化字符串 :-) 。曾尝试过将ATL::CString的format函数提取出来使用,但ATL::CString的底层调用了windows独有函数,无法跨越平台。当然,现在有了boost::format,我们不用再担心了。boost::format重载了'%'操作符,通过多次调用'%'操作符就能将参数非常方便格式化成字符串,并实现了ATL::CString和C#中的string两者的格式化字符串功能。除了语法刚开始感觉到怪异,功能足以让人感觉到兴奋!
一、boost::format工作的方式
基本的语法,boost::format( format-string ) % arg1 % arg2 % ... % argN
下面的例子说明boost::format简单的工作方式

















二、boost::format实际使用的实例
格式化语法: [ N$ ] [ flags ] [ width ] [ . precision ] type-char






































三、boost::format新的格式说明符
%{nt}
当n是正数时,插入n个绝对制表符
cout << boost::format("[%10t]") << endl;
%{nTX}
使用X做为填充字符代替当前流的填充字符(一般缺省是一个空格)
cout << boost::format("[%10T*]") << endl;
四、异常处理
一般写法:












boost::format的文档中有选择处理异常的办法,不过个人感觉实用性可能不强,下面是文档中的例子












#include <iostream>
#include <iomanip>
#include "boost/format.hpp"
#if !(BOOST_WORKAROUND(__GNUC__, < 3) && defined(__STL_CONFIG_H) )
// not for broken gcc stdlib
#include <boost/io/ios_state.hpp>
#else
// not as complete, but compatible with gcc-2.95 :
void copyfmt(ios& left, const ios& right) {
left.fill(right.fill());
left.flags(right.flags() );
left.exceptions(right.exceptions());
left.width(right.width());
left.precision(right.precision());
}
namespace boost {namespace io {
class ios_all_saver {
std::basic_ios<char> ios_;
std::ios & target_r;
public:
ios_all_saver(std::ios& right) : ios_(0), target_r(right) {
copyfmt(ios_, right);
}
~ios_all_saver() {
copyfmt(target_r, ios_);
}
};
}} // N.S. boost::io
// define showpos and noshowpos :
class ShowPos {
public:
bool showpos_;
ShowPos(bool v) : showpos_(v) {}
};
std::ostream& operator<<(std::ostream& os, const ShowPos& x) {
if(x.showpos_)
os.setf(ios_base:: showpos);
else
os.unsetf(ios_base:: showpos);
return os;
}
ShowPos noshowpos(false);
ShowPos showpos(true);
#endif // -end gcc-2.95 workarounds
//---------------------------------------------------------------------------//
// *** an exemple of UDT : a Rational class ****
class Rational {
public:
Rational(int n, unsigned int d) :
n_(n), d_(d) {
}
Rational(int n, int d); // convert denominator to unsigned
friend std::ostream& operator<<(std::ostream&, const Rational&);
private:
int n_; // numerator
unsigned int d_; // denominator
};
Rational::Rational(int n, int d) :
n_(n) {
if (d < 0) {
n_ = -n_;
d = -d;
} // make the denominator always non-negative.
d_ = static_cast<unsigned int> (d);
}
std::ostream& operator<<(std::ostream& os, const Rational& r) {
using namespace std;
streamsize n, s1, s2, s3;
streamsize w = os.width(0); // width has to be zeroed before saving state.
// boost::io::ios_all_saver bia_saver (os);
boost::io::basic_oaltstringstream<char> oss;
oss.copyfmt(os);
oss << r.n_;
s1 = oss.size();
oss << "/" << noshowpos; // a rational number needs only one sign !
s2 = oss.size();
oss << r.d_;
s3 = oss.size();
n = w - s3;
if (n <= 0) {
os.write(oss.begin(), oss.size());
} else if (os.flags() & std::ios_base::internal) {
std::streamsize n1 = w / 2, n2 = w - n1, t;
t = (s3 - s1) - n2; // is 2d part '/nnn' bigger than 1/2 w ?
if (t > 0) {
n1 = w - (s3 - s1); // put all paddings on first part.
n2 = 0; // minimal width (s3-s2)
} else {
n2 -= s2 - s1; // adjust for '/', n2 is still w/2.
}
os << setw(n1) << r.n_ << "/" << noshowpos << setw(n2) << r.d_;
} else {
if (!(os.flags() & std::ios_base::left)) {
// -> right align. (right bit is set, or no bit is set)
os << string(n, ' ');
}
os.write(oss.begin(), s3);
if (os.flags() & std::ios_base::left) {
os << string(n, ' ');
}
}
return os;
}
int main() {
using namespace std;
using boost::format;
using boost::io::group;
using boost::io::str;
string s;
Rational r(16, 9);
cout << "bonjour ! " << endl;
cout << r << endl;
// prints : "16/9"
cout << showpos << r << ", " << 5 << endl;
// prints : "+16/9, +5"
cout << format("%02d : [%0+9d] \n") % 1 % r;
cout << format("%02d : [%_+9d] \n") % 2 % Rational(9, 160);
cout << format("%02d : [%_+9d] \n") % 3 % r;
cout << format("%02d : [%_9d] \n") % 4 % Rational(8, 1234);
cout << format("%02d : [%_9d] \n") % 5 % Rational(1234, 8);
cout << format("%02d : [%09d] \n") % 6 % Rational(8, 1234);
cout << format("%02d : [%0+9d] \n") % 7 % Rational(1234, 8);
cout << format("%02d : [%0+9d] \n") % 8 % Rational(7, 12345);
/* output :
bonjour !
16/9
+16/9, +5
01 : [+016/0009]
02 : [+ 9/ 160]
03 : [+ 16/ 9]
04 : [ 8/1234]
05 : [1234/ 8]
06 : [0008/1234]
07 : [+1234/008]
08 : [+07/12345]
*/
cerr << "\n\nEverything went OK, exiting. \n";
return 0;
}