iostream examples


A manipulator is a value that can be inserted into or extracted from a stream to cause some special side effect. That is, some side effect besides inserting a representation of its value, or extracting characters and converting them to a value. A parameterized manipulator is a function (or a member of a class with an operator()) that returns a manipulator. Previous subtopic contain examples of the use of manipulators and parameterized manipulators. This subtopic contains examples illustrating how to define manipulators. The predefined manipulators and macros discussed in this subtopic are declared in the header file iomanip.h.

A (plain) manipulator is a function that takes an istream& or ostream& argument, operates on it in some way, and returns it. A (pointer to a) function of this type may be extracted from or inserted into a stream, respectively.

Many examples of manipulators (such as flush or endl) have already appeared in this paper. For example, a manipulator to insert a tab can be defined:

   ostream& tab(ostream& o) {
   	return o << '\t' ;
   cout << x << tab << y ;

This seems over elaborate. Why not simply define tab as a character or string? One possible reason has to do with the namespace. There can be only one (global) variable in a C++ program named tab but because of overloading there can be many functions with that name.

Another common use of manipulators is to shorten the long names and sequences of operations required by the iostream library. For example,

   ostream& fld(ostream& o) {
   	o.setf(ios::showbase,ios::showbase) ;
   	o.setf(ios::oct, ios::basefield) ;
   	o.width(10) ;
   	return o ;
   cout << fld << x ;

It is common for the function that manipulates a stream to need an auxiliary argument. setw() is an example of such a parameterized manipulator. To use parameterized manipulators the program must include iomanip.h.

For example, we might want to supply the value to be printed to fld in the above.

   ostream& fld(ostream& o, int n ) {
   	long f = flags(ios::showbase|ios::oct) ;
   	o << setw(10) << n ;
   	flags(f) ;	// restore original flags
   	return o ;

OMANIP(int) fld(int n) { return OMANIP(int)(fld,n) ; } ... cout << fld(23) ;

OMANIP is a macro and OMANIP(int) expands to the name of a class declared in iomanip.h. An OMANIP(int) insertion operator is also declared in iomanip.h and is used in the example. Note that fld in the above is overloaded; it is both the function that manipulates the stream and a function that returns an OMANIP(int).

If we need parameterized manipulators for parameter types other than int and long (which are declared in iomanip.h), they must be declared. For example, suppose we want to read numbers that may have a suffix.

   typedef long& Longref ;
   IOMANIPdeclare(Longref) ;
        // Declares IMANIP(Longref), OMANIP(Longref), IOMANIP(Longref)
        //          IAPP(Longref), OAPP(Longref), IOAPP(Longref)

istream& in_k(istream& i, long& n) { // Extract an integer. // If suffix is present multiply by 1024 i >> n ; if ( i.peek() == 'k' ) { i.ignore(1) ; n *= 1024 ; } return i ; }

IAPP(Intref) in_k = in_k ; // IAPP(Intref) is the type of an Intref applicator // in_k on right is function, on left variable

... long n ; cin >> in_k(n) ;

The IOMANIPdeclare(T) declares manipulators (and applicators) for type T. Because of the way the macro IOMANIPdeclare expands, the argument must be an identifier. In this case a typedef is required to create manipulators for long&. An applicator is something that behaves like a function returning a manipulator. That is, it is a class with an operator() member.

Sometimes we want a manipulator with more than one parameter. One way to achieve this effect is to define a manipulator on a class. For example, a manipulator that can be used to repeat a string might look like:

   cout << repeat("ab",3) << endl ;
to result in a line containing ``ababab.'' A possible definition of repeat would be
   struct Repeatpair {
   	const char* s ;
   	int n ;
   } ;

IOMANIPdeclare(Repeatpair) ;

static ostream& repeat(ostream& o, Repeatpair p) { // insert p.s into o, p.n times for ( int n = p.n ; n > 0 ; --n ) o << p.s ; return o ; }

OMANIP(Repeatpair) repeat(const char* s, int n) { Repeatpair p ; p.s=s ; p.n=n ; return OMANIP(Repeatpair)(repeat,p) ; }

Manipulators are a powerful and flexible method of extending the default inserters and extractors.

Next topic: The sequence abstraction
Previous topic: Miscellaneous formatting

© 2004 The SCO Group, Inc. All rights reserved.
UnixWare 7 Release 7.1.4 - 27 April 2004