cppannotations/yo/overloading/manipulators.yo
Frank B. Brokken 43df12533c WIP removing will
git-svn-id: https://cppannotations.svn.sourceforge.net/svnroot/cppannotations/trunk@581 f6dd340e-d3f9-0310-b409-bdd246841980
2011-08-31 20:34:43 +00:00

59 lines
2.8 KiB
Text

In chapter ref(IOStreams) we saw constructions like tt(cout) lshift() tt(hex)
lshift() tt(13) lshift() to display the value 13 in hexadecimal format. One
may wonder by what magic the tt(hex) i(manipulator) accomplishes this. In this
section the construction of manipulators like tt(hex) is covered.
Actually the construction of a manipulator is rather simple. To start, a
definition of the manipulator is needed. Let's assume we want to create a
manipulator tt(w10) which sets the i(field width) of the next field to be
written by the tt(ostream) object to 10. This manipulator is constructed as a
function. The tt(w10) function needs to know about the tt(ostream) object
in which the width must be set. By providing the function with an tt(ostream
&) parameter, it obtains this knowledge. Now that the function knows about the
tt(ostream) object we're referring to, it can set the width in that object.
Next, it must be possible to use the manipulator in an insertion
sequence. This implies that the i(return value) of the manipulator must be
a i(reference) to an ti(ostream) object also.
From the above considerations we're now able to construct our tt(w10)
function:
verbinclude(examples/w10.cc)
The tt(w10) function can of course be used in a `stand alone' mode, but it
can also be used as a manipulator. E.g.,
verbinclude(examples/w10use.cc)
The tt(w10) function can be used as a manipulator because the tt(class
ostream) has an overloaded oplshift() accepting a i(pointer to a function)
expecting an tt(ostream &) and returning an tt(ostream &). Its definition is:
verb(
ostream& operator<<(ostream &(*func)(ostream &str))
{
return (*func)(*this);
}
)
In addition to the above overloaded oplshift() another one is defined
verb(
ostream &operator<<(ios_base &(*func)(ios_base &base))
{
(*func)(*this);
return *this;
}
)
This latter function is used when inserting, e.g., tt(hex) or
tt(internal).
The above procedure does not work for manipulators requiring arguments.
It is of course possible to overload oplshift() to accept an tt(ostream)
reference and the address of a function expecting an tt(ostream &) and, e.g.,
an tt(int), but while the address of such a function may be specified with the
lshift()-operator, the arguments itself cannot be specified. So, one wonders
how the following construction has been implemented:
verb(
cout << setprecision(3)
)
In this case the manipulator is defined as a i(macro). Macro's, however,
are the realm of the i(preprocessor), and may easily suffer from unwelcome
side-effects. In bf(C++) programs they should be avoided whenever
possible. The following section introduces a way to implement manipulators
requiring arguments without resorting to macros, but using
hi(manipulator: as objects) anonymous objects.