3

I need to implement a C++ iostream manipulator. Reading here and there it seems that people uses 2 ways

  1. using ios_base::xalloc and ios_base::iword

  2. implementing a derived class from iostream like example below.

I like the second way but probably it has cons that I cannot see or understand compared to the first way.

    // Example of point 2
    struct mystream : public iostream
    {  
      ostream& o_;
      mystream(ostream& o) : o_(o) {} 

      ostream& operator << (int a) {
        // do something with o and a
        o << "<A>" << a << "</A>";
        return *this;
      }     
     };

     ostream mymanipulator(ostream& out) { 
       return mystream(out);
     }

I found a very good implementation of way #2 in this post Custom manipulator for C++ iostream.

It looks to me that xalloc and iword are more used to store some custom internal state for my custom stream to be used at some point.

Community
  • 1
  • 1
Abruzzo Forte e Gentile
  • 14,423
  • 28
  • 99
  • 173
  • What's the actual use case you're trying to implement? I have used xalloc() to great effect before but it's not for every use case. – John Zwinck May 29 '14 at 13:01
  • Nothing to answer - if you have an internal state to save (1) - otherwise (2) –  May 29 '14 at 13:02
  • @John it is a manipulator for HTML object..Anyway I think about these 2 topics like Dieter is going: saving a state vs. something else. – Abruzzo Forte e Gentile May 29 '14 at 13:07

1 Answers1

3

I wouldn't recommend either of those things.

Using ios_base::xalloc and ios_base::iword

You haven't exactly told us how you would use the data stored in the stream, but it's a bit unintuitive to set iword() each and every time you want to write.

Implementing a derived class from iostream...

Normally you don't want to inherit from the stream base classes. The only case in which it might be useful is when you're wrapping a custom stream around a stream buffer, but that's usually for convenience.

Another problem is that your inserter returns std::ostream, meaning that when chaining operators you'll only be writing to the std::ostream base object on the second write:

mystream str;
str << 100  // writes "<A>100</A>"
    << 200; // only writes 200

The idiomatic solution is to customize a std::num_put<char> facet for your stream's locale. This way you wrap the functionality directly under the hood of the stream so that it doesn't change the way the user uses the stream.

David G
  • 94,763
  • 41
  • 167
  • 253
  • ok. For the ostream returned by value you are right; it doesn't make sense..I found this code that does better http://stackoverflow.com/questions/535444/custom-manipulator-for-c-iostream/535647#535647. For the num_put I am reading this http://stackoverflow.com/questions/13335193/sticky-custom-stream-manipulatoryet ..looks intreaguing... – Abruzzo Forte e Gentile May 29 '14 at 14:47
  • 1
    This document is from 2001 but is useful to tell you about facets: http://www.drdobbs.com/the-standard-librarian-defining-a-facet/184403785#4 – CashCow Nov 06 '14 at 10:48
  • I'd like an explanation of why " it's a bit unintuitive to set iword() each and every time you want to write." iword() and pword() (properly encapsulated) seem much superior to a facet, which has to be imbued into the locale and the stream each time it changes. – Spencer Nov 01 '16 at 20:07
  • @Spencer I'm not sure why I said that. Of course setting `iword` and `pword` is much more efficient than imbuing and unimbuing a locale whenever we want different functionality. – David G Nov 01 '16 at 20:29