mirror of
https://github.com/boostorg/format.git
synced 2026-01-26 06:32:14 +00:00
862 lines
32 KiB
HTML
862 lines
32 KiB
HTML
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
|
|
|
|
<HTML><HEAD><TITLE>The Boost Format library</TITLE>
|
|
<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
|
|
</HEAD>
|
|
<BODY bgColor=white text=black>
|
|
|
|
<H1><IMG align=middle alt="c++boost.gif (8819 bytes)" height=86
|
|
src="../../../c++boost.gif" width=277>The Boost Format library</H1>
|
|
<P>The <CODE>
|
|
<A href="../../../boost/format.hpp"><boost/format.hpp></A></CODE>
|
|
format class provides printf-like formatting, in a type-safe manner which allows output of
|
|
user-defined types.
|
|
<br>
|
|
</P>
|
|
<ul>
|
|
<li><a href="#synopsis">Synopsis</a> </li>
|
|
<li><a href="#how_it_works">How it works</a> </li>
|
|
<li><a href="#examples">Examples</a> </li>
|
|
<li><a href="#syntax">Syntax</a>
|
|
<ul>
|
|
<li><a href="#printf_directives">printf format-specification syntax</a> </li>
|
|
<li><a href="#printf_differences">Incompatibilities with printf</a> </li>
|
|
</ul>
|
|
</li>
|
|
<li><a href="#manipulators">Manipulators and the internal stream state</a> </li>
|
|
<li><a href="#user-defined">User-defined types</a> </li>
|
|
<li><a href="#exceptions">Exceptions</a></li>
|
|
<li><a href="#performance">Performance</a></li>
|
|
<li><a href="#extract">Class Interface Extract</a></li>
|
|
<li><a href="#alternatives">Alternatives</a> </li>
|
|
</ul>
|
|
<a name="synopsis"></a>
|
|
<hr>
|
|
<H2>Synopsis</H2>
|
|
<P>A format object is constructed from a format-string, and is then given arguments through
|
|
repeated calls to <i>operator%</i>.
|
|
<br>
|
|
Each of those arguments are then converted to strings, who are in turn combined into one string,
|
|
according to the format-string.
|
|
</P>
|
|
<BLOCKQUOTE><PRE>
|
|
cout << boost::format("writing %1%, x=%2% : %3%-th try") % "toto" % 40.23 % 50;
|
|
// prints "writing toto, x=40.230 : 50-th try"
|
|
</PRE></BLOCKQUOTE>
|
|
|
|
<a name="how_it_works"></a>
|
|
<hr>
|
|
<H2>How it works</H2>
|
|
<ol>
|
|
<li>When you call <i>format(s)</i>, where s is the format-string, it constructs an object,
|
|
which parses the format string and look for all directives in it and prepares internal structures
|
|
for the next step.</li>
|
|
<li>
|
|
Then, either immediately,
|
|
as in <BLOCKQUOTE><PRE>cout << format("%2% %1%") % 36 % 77 )</PRE></BLOCKQUOTE>
|
|
or later on, as in
|
|
<BLOCKQUOTE><PRE>format fmter("%2% %1%");
|
|
fmter % 36; fmter % 77;</PRE></BLOCKQUOTE>
|
|
you <i>feed</i> variables into the formatter.
|
|
<br>those variables are dumped into an internal stream,
|
|
which state is set according to the given formatting options in the format-string
|
|
-if there are any-,
|
|
and the format object stores the string results for the last step.
|
|
</li>
|
|
<li>Once all arguments have been fed you can dump the format object to a stream,
|
|
or get its string value by using the
|
|
<i>str()</i> member function, or the free function <i>str(const format& )</i> in namespace <i>boost</i>. The result string stays accessible in the format object until another argument is passed,
|
|
at which time it is reinitialised.
|
|
|
|
<BLOCKQUOTE><PRE>
|
|
|
|
// fmter was previously created and fed arguments, it can print the result :
|
|
cout << fmter ;
|
|
|
|
// You can take the string result :
|
|
string s = fmter.str();
|
|
|
|
// possibly several times :
|
|
s = fmter.str( );
|
|
|
|
// You can also do all steps at once :
|
|
cout << boost::format("%2% %1%") % 36 % 77;
|
|
|
|
// using the str free function :
|
|
string s2 = str( format("%2% %1%") % 36 % 77 );
|
|
|
|
</PRE></BLOCKQUOTE>
|
|
</li>
|
|
<li>
|
|
Optionnally, after step 3, you can re-use a format object and restart at step2 :
|
|
<i>fmter % 18 % 39; </i>
|
|
<br> to format new variables with the same format-string, saving the expensive processing
|
|
involved at step 1.
|
|
</li>
|
|
</ol>
|
|
All in all, the format class translates a format-string (with eventually printf-like directives)
|
|
into operations on an internal stream, and finally returns the result of the formatting,
|
|
as a string, or directly into an output stream.
|
|
|
|
<a name="examples"></a>
|
|
<hr>
|
|
<H2>Examples</H2>
|
|
|
|
<BLOCKQUOTE><PRE>
|
|
using namespace std;
|
|
using boost::format;
|
|
using boost::io::group;
|
|
</PRE></BLOCKQUOTE>
|
|
<ul>
|
|
<li> Simple output, with reordering :
|
|
<BLOCKQUOTE><PRE>
|
|
|
|
cout << format("%1% %2% %3% %2% %1% \n") % "11" % "22" % "333"; // 'simple' style.
|
|
|
|
</PRE></BLOCKQUOTE>
|
|
It prints : "11 22 333 22 11 \n"
|
|
</li>
|
|
|
|
<li> More precise formatting, with Posix-printf positional directives :
|
|
<BLOCKQUOTE><PRE>
|
|
|
|
cout << format("(x,y) = (%1$+5d,%2$+5d) \n") % -23 % 35; // Posix-Printf style
|
|
|
|
</PRE></BLOCKQUOTE>
|
|
It prints : "(x,y) = ( -23, +35) \n"
|
|
</li>
|
|
|
|
<li> classical printf directive, no reordering :
|
|
<BLOCKQUOTE><PRE>
|
|
|
|
cout << format("writing %s, x=%s : %d-th step \n") % "toto" % 40.23 % 50;
|
|
|
|
</PRE></BLOCKQUOTE>
|
|
It prints : "writing toto, x=40.23 : 50-th step \n"
|
|
</li>
|
|
|
|
<li> Several ways to express the same thing :
|
|
<BLOCKQUOTE><PRE>
|
|
|
|
cout << format("(x,y) = (%+5d,%+5d) \n") % -23 % 35;
|
|
cout << format("(x,y) = (%|+5|,%|+5|) \n") % -23 % 35;
|
|
|
|
cout << format("(x,y) = (%1$+5d,%2$+5d) \n") % -23 % 35;
|
|
cout << format("(x,y) = (%|1$+5|,%|2$+5|) \n") % -23 % 35;
|
|
|
|
</PRE></BLOCKQUOTE>
|
|
all those print : "(x,y) = ( -23, +35) \n"
|
|
|
|
</li>
|
|
|
|
<li> Using manipulators to modify the format-string :
|
|
<BLOCKQUOTE><PRE>
|
|
|
|
format fmter("_%1$+5d_ %1$d \n");
|
|
|
|
format fmter2("_%1%_ %1% \n");
|
|
fmter2.modify_item(1, group(showpos, setw(5)) );
|
|
|
|
cout << fmter % 101 ;
|
|
cout << fmter2 % 101 ;
|
|
|
|
</PRE></BLOCKQUOTE>
|
|
Both print the same : "_ +101_ 101 \n"
|
|
</li>
|
|
|
|
<li> Using manipulators with arguments :
|
|
<BLOCKQUOTE><PRE>
|
|
|
|
cout << format("_%1%_ %1% \n") % group(showpos, setw(5), 101);
|
|
|
|
</PRE></BLOCKQUOTE>
|
|
The manipulators are applied at each occurence of %1%, and thus it prints : "_ +101_ +101 \n"
|
|
</li>
|
|
|
|
<li> New formatting feature : 'absolute tabulations', useful inside loops,
|
|
to insure a field is printed at the same position from one line to the next,
|
|
even if the widthes of the previous arguments can vary a lot.
|
|
|
|
<BLOCKQUOTE><PRE>
|
|
|
|
for(unsigned int i=0; i < names.size(); ++i)
|
|
cout << format("%1%, %2%, %|40t|%3%\n") % names[i] % surname[i] % tel[i];
|
|
|
|
</PRE></BLOCKQUOTE>
|
|
|
|
For some std::vector <i>names</i>, <i>surnames</i>, and <i>tel</i> (see sample_new_features.cpp) it prints :
|
|
<BLOCKQUOTE><PRE>
|
|
Marc-François Michel, Durand, +33 (0) 123 456 789
|
|
Jean, de Lattre de Tassigny, +33 (0) 987 654 321
|
|
</PRE></BLOCKQUOTE>
|
|
|
|
|
|
</li>
|
|
|
|
</ul>
|
|
|
|
<hr>
|
|
<H2>Sample Files</H2>
|
|
<P>The program <A href="../example/sample_formats.cpp">sample_formats.cpp</A>
|
|
demonstrates simple uses of <B>format</B>.
|
|
<br>
|
|
<P><A href="../example/sample_new_features.cpp">sample_new_features.cpp</A>
|
|
illustrates the few formatting features that were added to printf's syntax such as
|
|
simple positional directives, centered alignment, and 'tabulations'.
|
|
<br>
|
|
<P><A href="../example/sample_advanced.cpp">sample_advanced.cpp</A>
|
|
demonstrates uses of advanced features, like reusing, and modifying, format objects, etc..
|
|
<br>
|
|
<P>And <A href="../example/sample_userType.cpp">sample_userType.cpp</A>
|
|
shows the behaviour of the <b>format</b> library on user-defined types.
|
|
</P>
|
|
|
|
|
|
<a name="syntax"></a>
|
|
<hr>
|
|
<H2>Syntax</H2>
|
|
<P>
|
|
<b>boost::format( </b> format-string <b> ) %</b> arg1 <b>%</b> arg2 <b>%</b> ... <b>%</b> argN
|
|
|
|
</P>
|
|
|
|
<P>
|
|
The <i>format-string</i> contains text in which special directives will be replaced by
|
|
strings resulting from the formatting of the given arguments.
|
|
<br>The legacy syntax in the C and C++ worlds is the one used by printf, and thus format can use
|
|
directly printf format-strings, and produce the same result (in almost all cases. see
|
|
<a href="#printf_differences">Incompatibilities with printf</a> for details)
|
|
<br>
|
|
This core syntax was extended, to allow new features, but also to adapt to the C++ streams context.
|
|
Thus, format accepts several forms of directives in format-strings :
|
|
<UL>
|
|
<li> Legacy printf format strings : <B>%</B><i>spec</i><b></b> where <i>spec</i> is a
|
|
<a href="#printf_directives">printf format specification</a>
|
|
<br><i>spec</i> passes formatting options, like width, alignment, numerical base used for
|
|
formatting numbers,
|
|
as well as other specific flags.
|
|
But the classical <i>type-specification</i> flag of printf has a weaker meaning
|
|
in format. It merely sets the appropriate flags on the internal stream,
|
|
and/or formatting parameters,
|
|
but does not require the corresponding argument to be of a specific type.
|
|
<br>
|
|
e.g. : the specification <i>2$x</i>,
|
|
meaning "print argument number 2, which is an integral number, in hexa" for printf,
|
|
merely means "print argument 2 with stream basefield flags set to <i>hex</i>" for format.
|
|
</li>
|
|
<li><B>%|</B><i>spec</i><b>|</b> where <i>spec</i> is a printf format specification.
|
|
<br>
|
|
The brackets are introduced, to improve the readability of the format-string,
|
|
but primarily, to make the <i>type-conversion character</i> optional
|
|
in <i>spec</i>. This information is not necessary with C++ variables,
|
|
but with direct printf syntax, it is necessary to always give a type-conversion character,
|
|
merely because this character is crucial to determine the end of a format-specification.
|
|
<br>
|
|
e.g. : "%|-5|" will format the next variable with width set to 5, and left-alignment
|
|
just like the following printf directives : "%-5g", "%-5f", "%-5s" ..
|
|
</li>
|
|
<li> <b>%</b><i>N</i><b>%</b> <br>This simple positional notation
|
|
requests the formatting of the <i>N</i>-th argument - wihout any formatting option.
|
|
<br>
|
|
(It's merely a shortcut to Printf's positional directives (like "%<i>N</i>$s"),
|
|
but a major benefit is that it's much more readable, and
|
|
does not use a "type-conversion" character)
|
|
</li>
|
|
</UL>
|
|
On top of the standard printf format specifications, new features were implemented, like centered alignment. See <a href="#new_directives">new format specification</a> for details.
|
|
|
|
<a name="printf_directives"></a>
|
|
<h3>printf format specifications</h3>
|
|
<p>
|
|
The printf format specifications supported by Boost.format follows the Unix98
|
|
<a href="http://www.opengroup.org/onlinepubs/7908799/xsh/fprintf.html">Open-group printf</a>
|
|
precise syntax, rather than the standard C printf, which does not support positional arguments.
|
|
(Common flags have the same meaning in both, so it should not be a headache for anybody)
|
|
<br>
|
|
<i> Note that it is an error to use positional format specifications</i>
|
|
(e.g. <i>%3$+d</i>)
|
|
<i> mixed with non-positional ones</i> (e.g. <i>%+d</i>) <i>in the same format string.</i>
|
|
<br>
|
|
In the Open-group specification, referring to the same argument several times (e.g. <i>"%1$d %1$d"</i>) has undefined behaviour. Boost.format's behaviour in such cases is to allow each argument to be reffered to any number of times. The only constraint is
|
|
that it expects exactly <i>P</i> arguments, <i>P</i> being the maximum argument number used in the
|
|
format string. (e.g., for "%1$d %10$d", <i>P</i> == 10 ).
|
|
<br>Supplying more, or less, than <i>P</i> arguments raises an exception.
|
|
(unless it was set otherwise, see <a href="#exceptions">exceptions</a>)
|
|
</p>
|
|
<p>
|
|
<br>
|
|
<br>
|
|
A specification <i>spec</i> has the form :
|
|
[ <i>N</i><b>$</b> ] [ <i>flags</i> ] [ <i>width</i> ]
|
|
[ <b>.</b> <i>precision</i> ] <i>type-char</i>
|
|
<br>
|
|
<br>
|
|
Fields insided square brackets are optional.
|
|
Each of those fields are explained one by one in the following list :
|
|
</p>
|
|
|
|
<ul>
|
|
<li>
|
|
<i>N</i> <b>$</b> (optional field) specifies that the format specification applies to the <i>N</i>-th argument. (it is called a <i>positional format specification</i>)
|
|
<br>If this is not present, arguments are taken one by one. (and it is then an error to later supply an argument number)
|
|
<li>
|
|
<i>flags</i> is a sequences of any of those :
|
|
<blockquote>
|
|
<table border="1" cellpadding="5">
|
|
<tr> <td><b>Flag</b></td> <td><b>Meaning</b></td> <td><b>effect on internal stream</b></td>
|
|
</tr>
|
|
|
|
<tr> <td><b>'-'</b></td> <td>left alignment</td>
|
|
<td>N/A (applied later on the string)</td>
|
|
</tr>
|
|
<tr>
|
|
<td><b>'='</b></td> <td>centered alignment</td>
|
|
<td>N/A (applied later on the string)
|
|
<br><i>- note : added feature, not in printf -</i>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td><b>'_'</b></td> <td>internal alignment</td>
|
|
<td>sets internal alignment
|
|
<br><i>- note : added feature, not in printf -</i>
|
|
</td>
|
|
</tr>
|
|
|
|
<tr> <td><b>'+'</b></td> <td>show sign even for positive numbers</td>
|
|
<td>sets <i>showpos</i></td>
|
|
</tr>
|
|
<tr>
|
|
<td><b>'#'</b></td>
|
|
<td>show numerical base, and decimal point</td>
|
|
<td>sets <i>showbase</i> and <i>showpoint</i></td>
|
|
</tr>
|
|
<tr>
|
|
<td><b>'0'</b></td>
|
|
<td>pad with 0's (inserted after sign or base indicator)</td>
|
|
<td>if not left-aligned, calls <i>setfill('0')</i> and sets <i>internal</i>
|
|
<br> Extra actions are taken after stream conversion to handle
|
|
<a href="#user-defined">user-defined output</a>. </td>
|
|
</tr>
|
|
<tr>
|
|
<td><b>' '</b></td>
|
|
<td>if the string does not begin with <i>+</i> or <i>-</i>,
|
|
insert a <i>space</i> before the converted string</td>
|
|
<td>N/A (applied later on the string)
|
|
<br>Different to printf's behaviour : it is not affected by internal alignment</td>
|
|
</tr>
|
|
|
|
</table>
|
|
</blockquote>
|
|
</li>
|
|
|
|
<li>
|
|
<i>width</i> specifies a minimal width for the string resulting form the conversion.
|
|
If necessary, the string will be padded with alignment and fill characters either set on the stream via manipulators, or specified by the format-string (e.g. flags '0', '-', ..)
|
|
<br>
|
|
Note that width is not just set on the conversion stream.
|
|
To support output of <a href="#user-defined">user-defined types</a>
|
|
(that might call <i>operator<<</i> many times on several members),
|
|
the width is handled after stream conversion of the whole argument object,
|
|
in the format class code.
|
|
<li>
|
|
<i>precision</i> (preceded by a point), sets the stream's <i>precision</i>
|
|
<ul>
|
|
<li>When outputting a floatting type number, it sets the maximum number of digits
|
|
<ul><li>after decimal point when in fixed or scientific mode</li>
|
|
<li>in total when in default mode ('<i>general mode</i>', like <i>%g</i>) </li>
|
|
</ul>
|
|
<li>When used with type-char <b>s</b> or <b>S</b> it takes another meaning :
|
|
the conversion string is truncated to the <i>precision</i> first chars.
|
|
(Note that the eventual padding to <i>width</i> is done after truncation.)
|
|
</li>
|
|
</ul>
|
|
</li>
|
|
<li>
|
|
<i>type-char</i>. it does <b>not</b> impose the concerned argument to be of a restricted set
|
|
of types, but merely sets the flags that are associated with this type specification.
|
|
|
|
<blockquote>
|
|
<table border="1" cellpadding="5">
|
|
<tr>
|
|
<td><b>Type-Char</b></td>
|
|
<td><b>Meaning</b></td>
|
|
<td><b>effect on stream</b></td>
|
|
</tr>
|
|
<tr>
|
|
<td><b>p or x</b></td>
|
|
<td>hexadecimal output</td>
|
|
<td>sets <i>hex</i></td>
|
|
</tr>
|
|
<tr>
|
|
<td><b>o</b></td>
|
|
<td>octal output</td>
|
|
<td>sets <i>oct</i></td>
|
|
</tr>
|
|
<tr>
|
|
<td><b>e</b></td>
|
|
<td>scientific float format</td>
|
|
<td>sets floatfield bits to <i>scientific</i></td>
|
|
</tr>
|
|
<tr>
|
|
<td><b>f</b></td>
|
|
<td>fixed float format</td>
|
|
<td>sets floatfield bits to <i>fixed</i></td>
|
|
</tr>
|
|
<tr>
|
|
<td><b>g</b></td>
|
|
<td>general -default- float format</td>
|
|
<td><b>unset</b> all floatfield bits</td>
|
|
</tr>
|
|
<tr>
|
|
<td><b>X, E</b> or <b>G</b></td>
|
|
<td>same effect as their lowercase counterparts,
|
|
but using uppercase letters for number outputs. (exponents, hex digits, ..)</td>
|
|
<td>same effects as <i>'x'</i>, <i>'e'</i>, or <i>'g'</i>,
|
|
<b>plus</b> <i>uppercase</i></td>
|
|
</tr>
|
|
|
|
<tr>
|
|
<td><b>d, i</b> or <b>u</b></td>
|
|
<td><b>decimal</b> type output</td>
|
|
<td>sets basefield bits to <i>dec</i></td>
|
|
</tr>
|
|
<tr>
|
|
<td><b>s</b> or <b>S</b></td>
|
|
<td>string output</td>
|
|
<td><i>precision</i> specification is unset,
|
|
and its value goes to an internal field for later 'truncation'.
|
|
(see <i>precision</i> explanation above) </td>
|
|
</tr>
|
|
<tr>
|
|
<td><b>c</b> or <b>C</b></td>
|
|
<td>1-character output</td>
|
|
<td>only the first character of the conversion string is used.</td>
|
|
</tr>
|
|
<tr>
|
|
<td><b>%</b></td>
|
|
<td>print the character <i>%</i></td>
|
|
<td>N/A</td>
|
|
</tr>
|
|
</table>
|
|
</blockquote>
|
|
<p>Note that the 'n' type specification is ignored (and so is the corresponding argument),
|
|
because it does not fit in this context.
|
|
<br>
|
|
Also, printf 'l', 'L', or 'h' modifiers (to indicate wide, long or short types) are supported
|
|
(and simply have no effect on the internal stream).
|
|
</p>
|
|
|
|
</li>
|
|
</ul>
|
|
|
|
<a name="new_directives"></a>
|
|
<h3>new format-specifications</h3>
|
|
<ul>
|
|
<li> as stated in the flags table, centered and internal alignment flags (' <i>=</i> ',
|
|
and ' <i>_</i> ') were added.
|
|
</li>
|
|
<li> <i><b>%{</b>n</i><b>t}</b> , where <i>n</i> is a positive number,
|
|
inserts an <i>absolute tabulation</i>.
|
|
It means that format will, if needed, fill the string with characters, until
|
|
the length of the string created so far reaches <i>n</i> characters.
|
|
(see <a href="#examples">examples</a> )
|
|
</li>
|
|
<li> <b>%{</b><i>n</i><B>T</B><i>X</i><b>}</b> inserts a tabulation in the same way,
|
|
but using <i>X</i> as fill character instead of the current 'fill' char of the stream
|
|
(which is <i>space</i> for a stream in default state)
|
|
</li>
|
|
</ul>
|
|
|
|
<a name="printf_differences"></a>
|
|
<h2>Differences of behaviour vs printf</h2>
|
|
Suppose you have variables <i>x1, x2</i> (built_in types, supported by C's printf),
|
|
<br> and a format string <i>s</i> intended for use with a printf function this way :
|
|
<BLOCKQUOTE><PRE>
|
|
printf(s, x1, x2);
|
|
</PRE></BLOCKQUOTE>
|
|
<br>
|
|
In almost all cases, the result will be the same as with this command :
|
|
<BLOCKQUOTE><PRE>
|
|
cout << format(s) % x1 % x2;
|
|
</PRE></BLOCKQUOTE>
|
|
|
|
<p>
|
|
But because some printf format specifications don't translate well into stream formatting options,
|
|
there are a few notable imperfections in the way Boost.format emulates printf.<br>
|
|
In any case, the <i>format</i> class should quietly ignore the unsupported options, so
|
|
that printf format-strings are always accepted by format and produce almost the same
|
|
output as printf.
|
|
</p>
|
|
<br>Here is the full list of such differences :
|
|
<ul>
|
|
<li> <b>'0'</b> and <b>' '</b> options :
|
|
printf ignores these options for non numeric conversions, but format applies them to all
|
|
types of variables.
|
|
(so it is possible to use those options on user-defined types, e.g. a Rational class, etc..)
|
|
</li>
|
|
<li> <b>precision</b> for integral types arguments has a special meaning for printf :
|
|
<br> <i> printf( "(%5.3d)" , 7 ) ;</i> prints « ( 007) »
|
|
<br> While format, like streams, ignores the precision parameter for integral types conversions.
|
|
</li>
|
|
<li> the <b>'</b> printf option
|
|
(<i>format with thousands grouping characters)</i>)
|
|
has no effect in format.
|
|
</li>
|
|
<li> Width or precision set to asterisk (<i>*</i>) are used by printf to read this field from
|
|
an argument. e.g.
|
|
<i>printf("%1$d:%2$.*3$d:%4$.*3$d\n", hour, min, precision, sec);</i>
|
|
<br>This class does not support this mechanism for now. so such precision or width fields are quietly
|
|
ignored by the parsing.
|
|
</ul>
|
|
|
|
Also, note that the special <b>'n'</b> type-specification
|
|
(used to tell printf to save in a variable the number of characters output by the formatting)
|
|
has no effect in format.
|
|
<br> Thus format strings containing this type-specification should produce the same converted
|
|
string by printf or format.
|
|
It will not cause differences in the formatted strings between printf and format.
|
|
<br>To get the number of characters in the formatted string using Boost.Format,
|
|
you can use the <i>size()</i> member function :
|
|
<BLOCKQUOTE><PRE>
|
|
format formatter("%+5d");
|
|
cout << formatter % x;
|
|
unsigned int n = formatter.size();
|
|
</PRE></BLOCKQUOTE>
|
|
|
|
<a name="user-defined"></a>
|
|
<hr>
|
|
<h2>User-defined types output</h2>
|
|
<p>
|
|
All flags which are translated into modification to the stream state
|
|
act recursively within user-defined types.
|
|
( the flags remain active, and so does the desired format option, for each of
|
|
the '<<' operations that might be called by the user-defined class)
|
|
</p>
|
|
e.g., with a Rational class, we would have something like :
|
|
<BLOCKQUOTE><PRE>
|
|
Rational ratio(16,9);
|
|
cerr << format("%#x \n") % ratio; // -> "0x10/0x9 \n"
|
|
</PRE></BLOCKQUOTE>
|
|
|
|
<p>
|
|
It's a different story for other formatting options. For example, setting width applies
|
|
to the final output produced by the object, not to each of its internal outputs, and
|
|
that's fortunate :
|
|
</p>
|
|
<BLOCKQUOTE><PRE>
|
|
cerr << format("%-8d") % ratio; // -> "16/9 " and not "16 /9 "
|
|
cerr << format("%=8d") % ratio; // -> " 16/9 " and not " 16 / 9 "
|
|
</PRE></BLOCKQUOTE>
|
|
<p>
|
|
<br>But so does the 0 and ' ' options (contrarily to '+' which is directly translated to the stream
|
|
state by <i>showpos</i>. But no such flags exist for the zero and space printf options)
|
|
<br>and that is less natural :
|
|
</p>
|
|
<BLOCKQUOTE><PRE>
|
|
cerr << format("%+08d \n") % ratio; // -> "+00016/9"
|
|
cerr << format("% 08d \n") % ratio; // -> "000 16/9"
|
|
</PRE></BLOCKQUOTE>
|
|
It is possible to obtain a better behaviour by carefully designing the Rational's <i>operator<<</i>
|
|
to handle the stream's width, alignment and <i>showpos</i> paramaters by itself. This is demonstrated in
|
|
<A href="../example/sample_userType.cpp">sample_userType.cpp</A>.
|
|
|
|
<p></p>
|
|
|
|
<a name="manipulators"></a>
|
|
<hr>
|
|
<h3>Manipulators, and internal stream state</h3>
|
|
<P>
|
|
The internal stream state of <B>format</B> is saved before
|
|
and restored after output of an argument; therefore, the modifiers are not sticky and affect only
|
|
the argument they are applied to.
|
|
<br> The default state for streams, as stated by the standard, is :
|
|
precision 6, width 0, right alignment, and decimal flag set.
|
|
</P>
|
|
<P>
|
|
The state of the internal <B>format</B> stream can be changed by manipulators passed along
|
|
with the argument; via the <i>group</i> function, like that :
|
|
</p>
|
|
<BLOCKQUOTE><PRE>
|
|
cout << format("%1% %2% %1%\n") % group(hex, showbase, 40) % 50; // prints "0x28 50 0x28\n"
|
|
</PRE></BLOCKQUOTE>
|
|
<p>
|
|
<br>When passing N items inside a 'group' Boost.format needs to process manipulators
|
|
diferently from regular argument, and thus using group is subject to the following constraints :
|
|
<ol>
|
|
<li>the object to be printed must be passed as the last item in the group</li>
|
|
<li>the first N-1 items are treated as manipulators, and if they do produce output, it is discarded
|
|
</li>
|
|
</ol>
|
|
|
|
|
|
|
|
<p>
|
|
Such manipulators are passed to the streams right before the following argument,
|
|
at every occurence.
|
|
Note that formatting options specified within the format string are overridden
|
|
by stream state modifiers passed this way. For instance in the following code,
|
|
the <i>hex</i> manipulator has priority over the <i>d</i> type-specification in
|
|
the format-string which would set decimal output :
|
|
</P>
|
|
<BLOCKQUOTE><PRE>
|
|
cout << format("%1$d %2% %1%\n") % group(hex, showbase, 40) % 50;
|
|
// prints "0x28 50 0x28\n"
|
|
</PRE></BLOCKQUOTE>
|
|
|
|
|
|
<H2>Alternatives</H2>
|
|
<ul>
|
|
<li>
|
|
<B>printf</B> is the classical alternative, that is not type safe and not extendable to user-defined types.
|
|
<li>
|
|
<a href="http://www.ece.ucdavis.edu/~kenelson/ofrstream.cc">ofrstream.cc</a>
|
|
by Karl Nelson's design was a big source of inspiration to this format class.
|
|
</li>
|
|
<li><a href="http://www.gabi-soft.fr/gabi-lib.tgz">James Kanze's library</a>
|
|
has a format class (in <i>srcode/Extended/format</i> ) which looks
|
|
very well polished. Its design has in common with this class the use of internal stream
|
|
for the actual conversions, as well as using operators to pass arguments.
|
|
(but his class, as ofrstream, uses <i>operator<< </i> rather <i>than operator%</i> )
|
|
</li>
|
|
<li><a href="http://groups.yahoo.com/group/boost/files/format3/">Karl Nelson's library</a>
|
|
was intented as demonstration of alternative solutions
|
|
in discussions on Boost's list for the design of Boost.format.
|
|
</li>
|
|
</ul>
|
|
|
|
|
|
<a name="exceptions"></a>
|
|
<hr>
|
|
<H2>Exceptions</H2>
|
|
<p>
|
|
Boost.format enforces a number of rules on the usage of format objects. The format-string must obeys
|
|
the syntax described above, the user must supply exactly the right number of arguments before outputting to the final destination, and if using modify_item or bind_arg, items and arguments index
|
|
must not be out of range.
|
|
<br>
|
|
When format detects that one of these rules is not satisfied, it raises a corresponding exception,
|
|
so that the mistakes don't go unnoticed and unhandled.
|
|
<br>
|
|
But the user can change this behaviour to fit his needs,
|
|
and select which types of errors may raise exceptions using the following functions :
|
|
</p>
|
|
<BLOCKQUOTE><PRE>
|
|
|
|
unsigned char exceptions(unsigned char newexcept); // query and set
|
|
unsigned char exceptions() const; // just query
|
|
|
|
</PRE></BLOCKQUOTE>
|
|
|
|
<p>
|
|
The user can compute the argument <i>newexcept</i> by combining the following atoms using binary arithmetic :
|
|
|
|
<ul>
|
|
<li> <b>boost::io::bad_format_string_bit</b> selects errors due to ill-formed format-strings.
|
|
</li>
|
|
|
|
<li> <b>boost::io::too_few_args_bit</b> selects errors due to asking for the srting result before all arguments are passed.
|
|
</li>
|
|
|
|
<li> <b>boost::io::too_many_args_bit</b> selects errors due to passing too many arguments.
|
|
</li>
|
|
|
|
<li> <b>boost::io::out_of_range_bit</b> select errors due to out of range index supplied by the user when calling
|
|
<i>modify_item</i> or other functions taking an item index (or an argument index)
|
|
</li>
|
|
|
|
<li> <b>boost::io::all_error_bits</b> selects all errors
|
|
</li>
|
|
|
|
<li> <b>boost::io::no_error_bits</b> selects no error.
|
|
</li>
|
|
|
|
</ul>
|
|
<p>
|
|
For instance, if you don't want Boost.format to detect bad number of arguments, you can define
|
|
a specific wrapper function for building format objects with the right exceptions settings :
|
|
</p>
|
|
<BLOCKQUOTE><PRE>
|
|
|
|
boost::format my_fmt(const std::string & f_string) {
|
|
using namespace boost::io;
|
|
format fmter(f_string);
|
|
fmter.exceptions( all_error_bits ^ ( too_many_args_bit | too_few_args_bit ) );
|
|
return fmter;
|
|
}
|
|
|
|
</PRE></BLOCKQUOTE>
|
|
|
|
It is then allowed to give more arguments than needed (they are simply ignored) :
|
|
|
|
<BLOCKQUOTE><PRE>
|
|
|
|
cout << my_fmt(" %1% %2% \n") % 1 % 2 % 3 % 4 % 5;
|
|
|
|
</PRE></BLOCKQUOTE>
|
|
|
|
And if we ask for the result before all arguments are supplied, the corresponding part of the
|
|
result is simply empty
|
|
|
|
<BLOCKQUOTE><PRE>
|
|
|
|
cout << my_fmt(" _%2%_ _%1%_ \n") % 1 ;
|
|
// prints " __ _1_ \n"
|
|
|
|
</PRE></BLOCKQUOTE>
|
|
|
|
<a name="performance"></a>
|
|
<hr>
|
|
<H2>A Note about performance</H2>
|
|
<p>
|
|
The performance of boost::format for formatting a few builtin type arguments with reordering can be compared
|
|
to that of Posix-printf, and of the equivalent stream manual operations to give a measure
|
|
of the overhead incurred.
|
|
The result may greatly depend on the compiler, standard library implementation, and the precise
|
|
choice of format-string and arguments.
|
|
</p>
|
|
<p>
|
|
Since common stream implementations eventually call functions of the printf family for the actual
|
|
formatting of numbers, in general printf will be noticeably faster than the direct stream operations
|
|
And due to to the reordering overhead (allocations to store the pieces of string,
|
|
stream initialisation at each item formatting, ..) the
|
|
direct stream operations would be faster than boost::format,
|
|
(one cas expect a ratio ranging from 2 to 5 or more)
|
|
</p>
|
|
<p>
|
|
When iterated formattings are a performance bottleneck, performance can be slightly increased by parsing
|
|
the format string into a format object, and copying it at each formatting, in the following way.
|
|
</p>
|
|
<BLOCKQUOTE><PRE>
|
|
const boost::format fmter(fstring);
|
|
dest << boost::format(fmter) % arg1 % arg2 % arg3 ;
|
|
</PRE></BLOCKQUOTE>
|
|
<p>
|
|
As an example of performance results, the author measured the time of execution of iterated formattings
|
|
with 4 different methods
|
|
</p>
|
|
<ol>
|
|
<li> posix printf </li>
|
|
<li> manual stream output (to a dummy <i>nullStream</i> stream sending the bytes into oblivion)</li>
|
|
<li> boost::format copied from a const object as shown above</li>
|
|
<li> the straigt boost::format usage </li>
|
|
</ol>
|
|
<p>
|
|
the test was compiled with g++-3.3.3 and the following timings were measured (in seconds, and ratios) :
|
|
</p>
|
|
<BLOCKQUOTE><PRE>
|
|
string fstring="%3$0#6x %1$20.10E %2$g %3$0+5d \n";
|
|
double arg1=45.23;
|
|
double arg2=12.34;
|
|
int arg3=23;
|
|
|
|
- release mode :
|
|
printf : 2.13
|
|
nullStream : 3.43, = 1.61033 * printf
|
|
boost::format copied : 6.77, = 3.1784 * printf , = 1.97376 * nullStream
|
|
boost::format straight :10.67, = 5.00939 * printf , = 3.11079 * nullStream
|
|
|
|
- debug mode :
|
|
printf : 2.12
|
|
nullStream : 3.69, = 1.74057 * printf
|
|
boost::format copied :10.02, = 4.72642 * printf , = 2.71545 * nullStream
|
|
boost::format straight :17.03, = 8.03302 * printf , = 4.61518 * nullStream
|
|
</PRE></BLOCKQUOTE>
|
|
|
|
|
|
<a name="extract"></a>
|
|
<hr>
|
|
<H2>Class Interface Extract</H2>
|
|
|
|
<BLOCKQUOTE><PRE>namespace boost {
|
|
|
|
template<class charT, class Traits=std::char_traits<charT> >
|
|
class basic_format
|
|
{
|
|
public:
|
|
typedef std::basic_string<charT, Traits> string_t;
|
|
typedef typename string_t::size_type size_type;
|
|
basic_format(const charT* str);
|
|
basic_format(const charT* str, const std::locale & loc);
|
|
basic_format(const string_t& s);
|
|
basic_format(const string_t& s, const std::locale & loc);
|
|
basic_format& operator= (const basic_format& x);
|
|
|
|
void clear(); // reset buffers
|
|
basic_format& parse(const string_t&); // clears and parse a new format string
|
|
|
|
string_t str() const;
|
|
size_type size() const;
|
|
|
|
// pass arguments through those operators :
|
|
template<class T> basic_format& operator%(T& x);
|
|
template<class T> basic_format& operator%(const T& x);
|
|
|
|
// dump buffers to ostream :
|
|
friend std::basic_ostream<charT, Traits>&
|
|
operator<< <> ( std::basic_ostream<charT, Traits>& , basic_format& );
|
|
|
|
// Choosing which errors will throw exceptions :
|
|
unsigned char exceptions() const;
|
|
unsigned char exceptions(unsigned char newexcept);
|
|
|
|
// ............ this is just an extract .......
|
|
}; // basic_format
|
|
|
|
typedef basic_format<char > format;
|
|
typedef basic_format<wchar_t > wformat;
|
|
|
|
|
|
// free function for ease of use :
|
|
template<class charT, class Traits>
|
|
std::basic_string<charT,Traits> str(const basic_format<charT,Traits>& f) {
|
|
return f.str();
|
|
}
|
|
|
|
|
|
} // namespace boost
|
|
</PRE></BLOCKQUOTE>
|
|
<P>
|
|
</P>
|
|
<hr>
|
|
<H2>Rationale</H2>
|
|
<p>This class's goal is to bring a better, C++, type-safe and type-extendable <i>printf</i>
|
|
equivalent to be used with streams.
|
|
</p>
|
|
Precisely, <b>format</b> was designed to provide the following features :
|
|
<ul>
|
|
<li> support positional arguments (required for internationalisation)
|
|
<li> accept an unlimited number of arguments.
|
|
<li> make formatting commands visually natural.
|
|
<li> support the use of manipulators to modify the display of an argument.
|
|
in addition to the format-string syntax.
|
|
<li> accept any types of variables, by relying on streams for the actual conversion
|
|
to string. This specifically concerns user-defined types, for which the formatting
|
|
options effects should be intuitively natural.
|
|
<li> provide printf-compatibility, as much as it makes sense in a type-safe and type-extendable
|
|
context.
|
|
</li>
|
|
</ul>
|
|
<p> In the process of the design, many issues were faced, and some choices were made, that
|
|
might not be intuitively right. But in each case they were taken for
|
|
<a href="choices.html">some reasons</a>.
|
|
</p>
|
|
<hr>
|
|
<H2>Credits</H2>
|
|
<P>The author of Boost format is Samuel Krempp. He used ideas from
|
|
Rüdiger Loos' format.hpp and Karl Nelson's formatting classes.
|
|
<HR>
|
|
|
|
<P>Revised 26 January, 2003</P>
|
|
<p>
|
|
<a href="http://validator.w3.org/check/referer"><img border="0"
|
|
src="http://www.w3.org/Icons/valid-html40"
|
|
alt="Valid HTML 4.0!" height="31" width="88"></a>
|
|
</p>
|
|
<P>© Samuel Krempp 2002</p>
|
|
<p> Use, modification, and distribution are subject to the Boost Software
|
|
License, Version 1.0. (See accompanying file <a href="../../../LICENSE_1_0.txt">
|
|
LICENSE_1_0.txt</a> or copy at <a href="http://www.boost.org/LICENSE_1_0.txt">
|
|
www.boost.org/LICENSE_1_0.txt</a>)</p>
|
|
|
|
<P></P>
|
|
<P> </P></BODY></HTML>
|