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;
}