My goal is to have an iomanip inserter with parameter that can be used to determine if a message will be printed to the stream (or not.) The idea is that a static mask will include bits set for the categories of messages that should be streamed (and bits cleared for messages to be discarded.) The inserter will be used to specify what category (or categories) a message belongs to and if the mask anded with the presented categories is not zero, the message would be streamed out. I have this working but with file scope mask and categories. It seems to me that (at least the category) could be stored with the stream using xalloc() to provide an index and iword() to store/retrieve values at that index but that seems not to be working for me. I have read various Internet references for these functions and my expectation is that sequential calls to xalloc() should return increasing values. In the code below the value returned is always 4. My second puzzlement is where the storage for the iword() backing store is held. Is this static for ostream? Part of every ostream object?
Code follows
#include <iostream>
#include <sstream>
// from http://stackoverflow.com/questions/2212776/overload-handling-of-stdendl
//
// g++ -o blah blah.cpp
//
// Adding an iomanip with argument as in
// http://stackoverflow.com/questions/20792101/how-to-store-formatting-settings-with-an-iostream
//
using namespace std;
// don't really want file scope variables... Can these be stored in stream?
static int pri=0; // value for a message
static int mask=1; // mask for enabled output (if pri&mask => output)
static int priIDX() { // find index for storing priority choice
static int rc = ios_base::xalloc();
return rc;
}
class setPri // Store priority in stream (but how to retrieve when needed?)
{
size_t _n;
public:
explicit setPri(size_t n): _n(n) {}
size_t getn() const {return _n;}
friend ostream& operator<<(ostream& os, const setPri& obj)
{
size_t n = obj.getn();
int ix = priIDX();
pri = os.iword(ix) = n; // save in stream (?) and to file scope variable
os << "setPri(" << n << ") ix:" << ix << " "; // indicate update
return os;
}
};
class MyStream: public ostream
{
// Write a stream buffer that discards if mask & pri not zero
class MyStreamBuf: public stringbuf
{
ostream& output;
public:
MyStreamBuf(ostream& str)
:output(str)
{}
// When we sync the stream with the output.
// 1) report priority mask (temporary)
// 2) Write output if same bit set in mask and priority
// 3) flush the actual output stream we are using.
virtual int sync ( )
{
int ix = priIDX();
int myPri(output.iword(ix));
output << "ix:" << ix << " myPri:" << myPri << '\n';
if( mask & pri) // can't use (myPri&mask)
output << ' ' << str();
str("");
output.flush();
return 0;
}
};
// My Stream just uses a version of my special buffer
MyStreamBuf buffer;
public:
MyStream(ostream& str)
:buffer(str)
{
rdbuf(&buffer);
}
};
int main()
{
MyStream myStream(cout);
myStream << setPri(1) << " this should output" << endl;
myStream << setPri(2) << " this should not output" << endl;
myStream << setPri(3) << " this should also output" << endl;
}
Note that in sync() the code tries to fetch the value from the stream but the returned value is always 0 as if it was not set to begin with.
In my searches to get to this point I have seen comments that it is not a good idea to subclass an ostream. Feel free to suggest a better alternative! (That I can understand. ;) )
Thanks!