Listing 2
#include <iostream> #include <ostream> using namespace std; // user-defined class with custom stream operators, // state object on the free store // the state object struct bracketing { bracketing(char l = '(', char r = ')') : left_(l), right_(r) {} char left_, right_; }; // the hypothetical complex class class mycomplex { double re_, im_; public: mycomplex(double r, double i) : re_(r), im_(i) {} static int myindex() { static int index = ios_base::xalloc(); return index; } static bracketing * mybrackets(ios_base &iob) { int index = myindex(); void *&p = iob.pword(index); bracketing *b = static_cast<bracketing*>(p); if (b == NULL) { // if this is new slot, put default value p = b = new bracketing; // and register a call-back for the slot iob.register_callback(mycallback, index); } return b; } ostream& print(ostream &os) const { // get the stream state (maybe default) from private slot and use it bracketing *b = mybrackets(os); return os << b->left_ << re_ << ", " << im_ << b->right_; } // other operations omitted private: // call-back function static void mycallback(ios_base::event e, ios_base &iob, int index) { if (e == ios_base::erase_event) { // just destroy the state object delete mybrackets(iob); } else if (e == ios_base::copyfmt_event) { void *&p = iob.pword(index); // do not leak any exception try { // perform deep copy in-place bracketing *old = static_cast<bracketing*>(p); p = new bracketing(*old); } catch (...) { // in case something goes wrong, clean the slot p = NULL; } } } }; ostream & operator<<(ostream &os, const mycomplex &cplx) { return cplx.print(os); } // convenience modifier with inserter operator bracketing setbrackets(char l, char r) { return bracketing(l, r); } ostream & operator<<(ostream &os, bracketing b) { // set the stream state in the private slot // a simple value-based assignment will do bracketing *pb = mycomplex::mybrackets(os); *pb = b; return os; } int main() { mycomplex c(3.14, 2.71); // use default bracketing style cout << c << endl; // change the bracketing style cout << setbrackets('[', ']'); cout << c << endl; }