Synopsis

A format object is constructed from a format-string, and is then given
arguments through repeated calls to operator%.
Each of those arguments are then converted to strings, who are in turn
combined into one string, according to the format-string.

How it works

When you call format(s), 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.

Then, either immediately, as in

cout << format("%2% %1%") % 36 % 77;

or later on, as in

format fmter("%2% %1%");
fmter % 36; fmter % 77;

you feed variables into the formatter.
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.

Once all arguments have been fed you can dump the format object to a
stream, or get its string value by using the str() member
function, or the free function str(const format& ) in
namespace boost. The result string stays accessible in the format
object until another argument is passed, at which time it is
reinitialised.

// 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 );

Optionnally, after step 3, you can re-use a format object and restart
at step2 : fmter % 18 % 39;
to format new variables with the same format-string, saving the expensive
processing involved at step 1.

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.

The manipulators are applied at each occurrence of %1%, and
thus it prints : "_ +101_ +101 \n"

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.

Syntax

boost::format( format-string ) % arg1 % arg2
% ... % argN

The format-string contains text in which special directives will
be replaced by strings resulting from the formatting of the given
arguments.
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 Incompatibilities with printf for details)
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 :

Legacy printf format strings : %spec where spec
is a printf format specificationspec passes formatting options, like width, alignment, numerical
base used for formatting numbers, as well as other specific flags. But
the classical type-specification 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.
e.g. : the specification 2$x, 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 hex" for
format.

%|spec| where spec is a printf format
specification.
This pipe-delimited syntax is introduced, to improve the readability of the
format-string, but primarily, to make the type-conversion
character optional in spec. 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.
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" ..

%N%
This simple positional notation requests the formatting of the
N-th argument - wihout any formatting option.
(It's merely a shortcut to Printf's positional directives (like
"%N$s"), but a major benefit is that it's much more readable, and
does not use a "type-conversion" character)

On top of the standard printf format specifications, new features were
implemented, like centered alignment. See new
format specification for details.

printf format specifications

The printf format specifications supported by Boost.format follows the
Unix98 Open-group
printf 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)Note that it is an error to use positional format specifications
(e.g. %3$+d) mixed with non-positional ones (e.g. %+d)
in the same format string.
In the Open-group specification, referring to the same argument several
times (e.g. "%1$d %1$d") 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 P
arguments, P being the maximum argument number used in the format
string. (e.g., for "%1$d %10$d", P == 10 ).
Supplying more, or less, than P arguments raises an exception.
(unless it was set otherwise, see exceptions)

Fields insided square brackets are optional. Each of those fields are
explained one by one in the following list :

N$ (optional field) specifies that the format
specification applies to the N-th argument. (it is called a
positional format specification)
If this is not present, arguments are taken one by one. (and it is then
an error to later supply an argument number)

flags is a sequences of any of those :

Flag

Meaning

effect on internal stream

'-'

left alignment

N/A (applied later on the string)

'='

centered alignment

N/A (applied later on the string)- note : added feature, not in printf -

'_'

internal alignment

sets internal alignment- note : added feature, not in printf -

'+'

show sign even for positive numbers

sets showpos

'#'

show numerical base, and decimal point

sets showbase and showpoint

'0'

pad with 0's (inserted after sign or base indicator)

if not left-aligned, calls setfill('0') and sets
internal
Extra actions are taken after stream conversion to handle
user-defined output.

' '

if the string does not begin with + or -,
insert a space before the converted string

N/A (applied later on the string)
Different to printf's behaviour : it is not affected by internal
alignment

width 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', '-', ..)
Note that width is not just set on the conversion stream. To support
output of user-defined types (that might call
operator<< many times on several members), the width is
handled after stream conversion of the whole argument object, in the
format class code.

precision (preceded by a point), sets the stream's
precision

When outputting a floatting type number, it sets the maximum
number of digits

after decimal point when in fixed or scientific mode

in total when in default mode ('general mode', like
%g)

When used with type-char s or S it takes another
meaning : the conversion string is truncated to the precision
first chars. (Note that the eventual padding to width is done
after truncation.)

type-char. it does not impose the concerned argument to
be of a restricted set of types, but merely sets the flags that are
associated with this type specification.

Type-Char

Meaning

effect on stream

p or x

hexadecimal output

sets hex

o

octal output

sets oct

e

scientific float format

sets floatfield bits to scientific

f

fixed float format

sets floatfield bits to fixed

g

general -default- float format

unset all floatfield bits

X, E or G

same effect as their lowercase counterparts, but using
uppercase letters for number outputs. (exponents, hex digits,
..)

same effects as 'x', 'e', or 'g',
plusuppercase

d, i or u

decimal type output

sets basefield bits to dec

s or S

string output

precision specification is unset, and its value goes
to an internal field for later 'truncation'. (see
precision explanation above)

c or C

1-character output

only the first character of the conversion string is
used.

%

print the character %

N/A

Note that the 'n' type specification is ignored (and so is the
corresponding argument), because it does not fit in this context.
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).

new format-specifications

as stated in the flags table, centered and internal alignment flags
(' = ', and ' _ ') were added.

%{nt} , where n is a positive number,
inserts an absolute tabulation. It means that format will, if
needed, fill the string with characters, until the length of the string
created so far reaches n characters. (see examples )

%|nTX| inserts a tabulation in the
same way, but using X as fill character instead of the current
'fill' char of the stream (which is space for a stream in default
state)

Differences of behaviour vs printf

Suppose you have variables
x1, x2 (built_in types, supported by C's printf),
and a format string s intended for use with a printf function this
way :

printf(s, x1, x2);

In almost all cases, the result will be the same as with this command :

cout << format(s) % x1 % x2;

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.
In any case, the format 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.

Here is the full list of such differences :

'0' and ' ' 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..)

the ' printf option (format with thousands grouping
characters)) has no effect in format.

Width or precision set to asterisk (*) are used by printf to
read this field from an argument. e.g.
printf("%1$d:%2$.*3$d:%4$.*3$d\n", hour, min, precision, sec);
This class does not support this mechanism for now. so such precision or
width fields are quietly ignored by the parsing.

Also, note that the special 'n' type-specification (used to
tell printf to save in a variable the number of characters output by the
formatting) has no effect in format.
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.
To get the number of characters in the formatted string using Boost.Format,
you can use the size() member function :

User-defined types output

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)

But so does the 0 and ' ' options (contrarily to '+' which is directly
translated to the stream state by showpos. But no such flags exist
for the zero and space printf options)
and that is less natural :

It is possible to obtain a better behaviour by carefully
designing the Rational's operator<< to handle the stream's
width, alignment and showpos paramaters by itself. This is
demonstrated in sample_userType.cpp.

Manipulators, and internal stream state

The internal stream state of format 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.
The default state for streams, as stated by the standard, is : precision 6,
width 0, right alignment, and decimal flag set.

The state of the internal format stream can be changed by
manipulators passed along with the argument; via the group function,
like that :

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 :

the object to be printed must be passed as the last item in the
group

the first N-1 items are treated as manipulators, and if they do
produce output, it is discarded

Such manipulators are passed to the streams right before the following
argument, at every occurrence. 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 hex manipulator has priority
over the d type-specification in the format-string which would set
decimal output :

Alternatives

printf is the classical alternative, that is not type safe and
not extendable to user-defined types.

ofrstream.cc by Karl Nelson's design was a big source of inspiration
to this format class.

James Kanze's library has a format class (in
srcode/Extended/format ) 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 operator<< rather than
operator% )

Karl
Nelson's library was intented as demonstration of alternative
solutions in discussions on Boost's list for the design of
Boost.format.

Exceptions

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.
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.
But the user can change this behaviour to fit his needs, and select which
types of errors may raise exceptions using the following functions :

It is then allowed to give more arguments than needed (they
are simply ignored) :

cout << my_fmt(" %1% %2% \n") % 1 % 2 % 3 % 4 % 5;

And if we ask for the result before all arguments are
supplied, the corresponding part of the result is simply empty

cout << my_fmt(" _%2%_ _%1%_ \n") % 1 ;
// prints " __ _1_ \n"

A Note about performance

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.

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)

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.

Rationale

This class's goal is to bring a better, C++, type-safe and
type-extendable printf equivalent to be used with
streams.

Precisely, format was designed to provide the following
features :

support positional arguments (required for internationalisation)

accept an unlimited number of arguments.

make formatting commands visually natural.

support the use of manipulators to modify the display of an argument.
in addition to the format-string syntax.

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.

provide printf-compatibility, as much as it makes sense in a
type-safe and type-extendable context.

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 some reasons.

Credits

The author of Boost format is Samuel Krempp. He used ideas from
Rüdiger Loos' format.hpp and Karl Nelson's formatting classes.