Creating Manipulators

Creating Simple Manipulators for Your Own Types

The I/O Stream Class Library gives you the facilities to create simple manipulators for your own types. Simple manipulators that manipulate istream objects are accepted by the following input operators:

istream istream::operator>> (istream&, istream& (*f) (istream&));
istream istream::operator>> (istream&, ios&(*f) (ios&));

Simple manipulators that manipulate ostream objects are accepted by the following output operators:

ostream ostream::operator<< (ostream&, ostream&(*f) (ostream&));
ostream ostream::operator<< (ostream&, ios&(*f) (ios&));

The definition of a simple manipulator depends on the type of object that it modifies. The following table shows sample function definitions to modify istream, ostream, and ios objects.

Class of object Sample function definition
istream istream &fi(istream&){ /*...*/ }
ostream ostream &fo(ostream&){ /*...*/ }
ios ios &fios(ios&){ /*...*/ }

For example, if you want to define a simple manipulator line that inserts a line of dashes into an ostream object, the definition could look like this:

ostream &line(ostream& os) {
   return os << "\n--------------------------------"
             << "--------------------------------\n";
   }

Thus defined, the line manipulator could be used like this:

cout << line << "WARNING! POWER-OUT IS IMMINENT!" << line << flush;

This statement produces the following output:

----------------------------------------------------------------
WARNING! POWER-OUT IS IMMINENT!
----------------------------------------------------------------

Creating Parameterized Manipulators for Your Own Types

The I/O Stream Class Library gives you the facilities to create parameterized manipulators for your own types. Follow these steps to create a parameterized manipulator that takes an argument of a particular type tp:

  1. Call the macro IOMANIPdeclare(tp). Note that tp must be a single identifier. For example, if you want tp to be a reference to a long double value, use typedef to make a single identifier to replace the two identifiers that make up the type label long double:
         typedef long double& LONGDBLREF 
  2. Determine the class of your manipulator. If you want to define an APP Parameterized manipulator, choose a class that has APP in its name (an APP class, also known as an applicator). If you want to define a MANIP Parameterized manipulator, choose a class that has MANIP in its name (a MANIP class). Once you have determined which type of class to use, the particular class that you choose depends on the type of object that the manipulator is going to manipulate. The following table shows the class of objects to be modified, and the corresponding manipulator classes.
    Class to be modified Manipulator class
    istream IMANIP(tp) or IAPP(tp)
    ostream OMANIP(tp) or OAPP(tp)
    iostream IOMANIP(tp) or IOAPP(tp)
    The ios part of istream objects or ostream objects SMANIP(tp) or SAPP(tp)
  3. Define a function f that takes an object of the class tp as an argument. The definition of this function depends on the class you chose in step 2, and is shown in the following table:
    Class chosen Sample definition
    IMANIP(tp) or IAPP(tp) istream &f(istream&, tp){/ *... */ }
    OMANIP(tp) or OAPP(tp) ostream &f(ostream&, tp){/* ... */ }
    IOMANIP(tp) or IOAPP(tp) iostream &f(iostream&, tp){/* ... */ }
    SMANIP(tp) or SAPP(tp) ios &f(ios&, tp){/* ... */ }
  4. Define the manipulator.

    Note: Parameterized manipulators defined with IOMANIP or IOAPP are not associative. This means that you cannot use such manipulators more than once in a single output statement.


Example of Defining an APP Parameterized Manipulator
Example of Defining a MANIP Parameterized Manipulator
Example of Nonassociative Parameterized Manipulators