1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030
|
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta http-equiv="Content-Language" content="en-us">
<meta http-equiv="Content-Type" content="text/html; charset=us-ascii">
<title>The Boost Format library</title>
</head>
<body bgcolor="white" text="black">
<h1><img align="middle" alt="boost.png (6897 bytes)" height="86" src=
"../../../boost.png" 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="#alternatives">Alternatives</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="#rationale">Rationale</a></li>
</ul><a name="synopsis" id="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" id="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" id="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>
<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>
<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>
<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" id="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 :</p>
<ul>
<li>Legacy printf format strings : <b>%</b><i>spec</i> 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" id=
"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>
<li>
<i>flags</i> is a sequences of any of those :
<blockquote>
<table border="1" cellpadding="5" summary="">
<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>
<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>
<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" summary="">
<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" id="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" id="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.</li>
</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" id="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>. <a name=
"manipulators" id="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 :</p>
<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><a name="alternatives" id="alternatives"></a>
<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>
<li>ofrstream.cc by Karl Nelson's design was a big source of inspiration
to this format class.</li>
<li>James Kanze's library 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" id="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 :</p>
<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" id="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" id="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>
<hr>
<a name="rationale" id="rationale"></a>
<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>
<li>accept an unlimited number of arguments.</li>
<li>make formatting commands visually natural.</li>
<li>support the use of manipulators to modify the display of an argument.
in addition to the format-string syntax.</li>
<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>
<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.</p>
<hr>
<p><a href="http://validator.w3.org/check?uri=referer"><img border="0" src=
"../../../doc/images/valid-html401.png" alt="Valid HTML 4.01 Transitional"
height="31" width="88"></a></p>
<p>Revised
<!--webbot bot="Timestamp" s-type="EDITED" s-format="%d %B, %Y" startspan -->02 December, 2006<!--webbot bot="Timestamp" endspan i-checksum="38510" --></p>
<p><i>Copyright © 2002 Samuel Krempp</i></p>
<p><i>Distributed under 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">http://www.boost.org/LICENSE_1_0.txt</a>)</i></p>
</body>
</html>
|