Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to write user-defined manipulators for streaming self-written class

Tags:

c++

iostream

How do I write user-defined stream manipulators in C++ that control the format of streaming a self-written class?

Specifically, how would I write simple manipulators verbose and terse to control the amount of output streamed?

My environment is GCC, versions 4.5.1 and up.

Example:

class A
{
 ...
};

A a;

// definition of manipulators verbose and terse

cout << verbose << a << endl; // outputs a verbosely
cout << terse << a << endl; // outputs a tersely

PS: What follows is just a side question, feel free to ignore it: Can this portably be extended to manipulators taking arguments? Josuttis writes in "The C++ Standard Library" near the end of section 13.6.1 that writing manipulators taking argument is implementation dependent. Is this still true?

like image 831
Peter G. Avatar asked Apr 28 '11 09:04

Peter G.


1 Answers

I don't see any reason for them to be implementation dependent.

This is comething that I use, for the actual manipulator, create a function that returns an instance of the following helper. If you need to store the data, just store it inside the helper, some global variable, singleton, etc...

    /// One argument manipulators helper
    template < typename ParType >
    class OneArgManip
    {
        ParType par;
        std::ostream& (*impl)(std::ostream&, const ParType&);

        public:
            OneArgManip(std::ostream& (*code)(std::ostream&, const ParType&), ParType p) 
                : par(p), impl(code) {}

            // calls the implementation
            void operator()(std::ostream& stream) const
            { impl(stream,par); }

            // a wrapper that allows us to use the manipulator directly
            friend std::ostream& operator << (std::ostream& stream, 
                            const OneArgManip<ParType>& manip)
            { manip(stream); return stream; }
    };

Example of a manipulator based on this:

OneArgManip<unsigned> cursorMoveUp(unsigned c) 
{ return OneArgManip<unsigned>(cursorMoveUpI,c); }

std::ostream& cursorMoveUpI(std::ostream& stream, const unsigned& c)
{ stream << "\033[" << c << "A"; return stream; }

For some explanation:

  1. u use the manipulator, that returns a new instance of the helper bound to an implementation of the helper
  2. stream tries to process the helper, that invokes the << overload on the helper
  3. that invokes the () operator on the helper
  4. that invokes the real implementation of the helper with the parameter passed from the original manipulator call

If you want I can post 2 param and 3 param helpers as well. The principle is the same though.

like image 123
Šimon Tóth Avatar answered Nov 10 '22 01:11

Šimon Tóth