News:

This week IPhone 15 Pro winner is karn
You can be too a winner! Become the top poster of the week and win valuable prizes.  More details are You are not allowed to view links. Register or Login 

Main Menu

C++ Tips: IO - Customizing IO manipulators (part I of III)

Started by ben2ong2, October 06, 2006, 11:13:13 PM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

ben2ong2

PROBLEM: You are not allowed to view links. Register or Login (John Weber)

   Sorry if this has been discussed before, but I couldn't find it in the
FAQ. Is there a generally accepted means of defining new manipulators for
iostreams. I have defined a class that I would like to control the output
format for using a manipulator specific to that class, but I'm not sure how to
go about it. Its seems the predefined manipulators set attributes on the
iostream object itself, but its not clear to me how I can extend this paradigm
for user defined things.


RESPONSE: You are not allowed to view links. Register or Login (James Kanze), 3 Aug 94

First, the manipulator must communicate with the insertion function
(operator>>).  This will take place through data in the ios class (the
base class for all iostreams).

Ios already defines a certain number of flags and parameters which can
be set and read from the outside.  Flags (use setf, unsetf to
manipulate), width, precision and fill are the ones used for
formatting.

If these are not enough, you can always get more; ios contains an
infinite large array, and all you have to do is allocate a word in it
for your use.  The function ios::xalloc() will return a unique integer
each time it is called; use this to avoid conflicts.  Thus, to acquire
a new flag word:

   static int   myFlagsIndex = -1 ;   // Visible to both the manip.
                  // and operator>>.

   //  To get a reference to your flags:
   if ( myFlagsIndex < 0 )
       myFlagsIndex = ios::xalloc() ;
   long&      myFlags = stream.iword( myFlagsIndex ) ;

If your manipulator doesn't require parameters, the job is simple:
just declare it as a function with the following signature:

   ios&
   myManip( ios& stream )
   {
       //  Set the flag bits...
       return stream ;
   }

If you need parameters, then the job is somewhat more complicated, and
you will in fact need two functions and a class for each manipulator.
If one parameter is sufficient, then have a look at iomanip.h (where
setw, et al. are declared).  This contains the generic class SMANIP
(or maybe the template class smanip on newer implementations), which
will generate the class automatically for you.  Anyhow:

- The class will be defined to have a constructor which takes the
arguments of the manipulator and saves them.  If you need several
manipulators with the same arguments, they can use the same class if
the class also requires and stores a pointer to function parameter.
(This is what SMANIP does.)

- The manipulator itself (what the user sees) will simply return an
instance of this class.  For example, if SMANIP(int) is used for the
class:

   SMANIP(int)
   myManip( int arg )
   {
       return SMANIP(int)( myManipFnc , arg ) ;
   }

In this case, myManipFnc (the second function, see below) is passed
as a parameter, since other manipulators (setw, for example) also
return an SMANIP.

- The second function looks as follows:

   ios&
   myManipFnc( ios& stream , int arg )
   {
       //  Set the flags in stream using arg.
       return stream ;
   }

- Finally, if you write your own class (because you need more than one
parameter, for example), you will have to declare and define
operator>> as a friend of the class.  This operator does nothing but
call your function; a glance at the inline code in iomanip should show
you all that is necessary.  (Frankly, I would avoid manipulators with
more than one parameter; in this case, you don't have to worry about
the class or operator>>.)

You are not allowed to view links. Register or Login
You are not allowed to view links. Register or Login