TITLE: printf-style output with streams (Newsgroups: comp.lang.c++.moderated, 9 Feb 99) KARR: dkarr@tcsi.com (David M. Karr) > In the past, I believe I've read about some cases where people have > developed classes which can specify a "printf" format string, but used > with iostreams. I didn't pay too much attention at the time, as I > never had to do very complicated formatting with iostreams. [snip] > I now see a very important need for this, but not for complex > formatting. I think it will make it easier to support i18n, where my > format strings are stored in a catalog (or app-defaults file). > > This would only really be practical if the format string class handled > the "%$Ns" format, which specifies a particular argument number. This > allows the code to insert arguments in a particular order, but the > format string will specify what order those parameters are placed in > the string. [snip] > Can someone point me to anything which can do this, either freeware or > commercial? KANZE: My implementation was done as an experiment, a long time ago, and I used whatever was handy to implement it quickly. Including some propriatory classes of my customer, so I can't make my implementation available. I don't know if Dietmar has anything available, but you might try his site. Other than that, if you don't need the formatting possibilities, and performance isn't a big problem, the implementation isn't that difficult. Basically, you need a class Format, with a constructor which takes the formatting string, and a private member : vector< string > params ; You use a template member function to format the individual arguments: template< class T > Format& Format::with( T const& obj ) { ostringstream s ; s << obj ; params.push_back( s.str() ) ; return *this ; } All that's left is an operator string() conversion function, which scans the format string, inserting param[ i ] where ever necessary. Extending this to handle width, the left and right adjust flags, and fill, should be pretty simple, since the effects of these flags can be done on the second scan. Handling things like precision or base, however, would require parsing the formatting string before starting, saving the various flags for each format specifier, then providing a member function getStream, which returns an ostringstream with the appropriate flags set. Alternatively, if there are only a few special formatting options which interest you (say precision), you can provide an overloaded version of the template function: template< class T > Format& Format::with( T const& obj , int precision ) ; Finally, in many cases, the preferred solution might be to provide special formatting classes, e.g.: template< int width , int prec > class Fixed { public: Fixed( double d ) : myD( d ) {} void output( ostream& s ) const { s << setw( width ) << setprecision( prec ) << myD ; } private: double myD ; } ; template< int width , int prec > ostream& operator<<( ostream& s , Fixed< width , prec > const& obj ) { obj.output( s ) ; return s ; } Given this, an output statement might be: cout << Format( gettext( fmt ) ).with( aDouble ).with( anInt ) << '\n'; The implicit conversion to string makes the standard operator<< work.