Reputation: 187
I want to put a text description of a class instance onto an ostream, as in
ostream << myInstance;
I know how to declare an ostream inserter;
ostream& operator<<(ostream&, myClass&);
I want to be able to put different levels of detail to the ostream. I could do this if I could define two or more ostream inserters, or pass an extra argument to the inserter, or pass a method to the inserter, or perhaps call a method that returns a stringstream (can I do that?)
Has anyone solved this problem?
Upvotes: 0
Views: 401
Reputation: 153929
The standard solution is to define a custom manipulator, using flags or
other formatting information stored in data provided by ios::xalloc
.
Something like:
int
flagIndex()
{
static int const theIndex = std::ostream::xalloc();
return theIndex;
}
std::ostream&
verbose( std::ostream& stream )
{
stream.iword( flagIndex() ) = 1;
return stream;
}
std::ostream&
unverbose( std::ostream& stream )
{
stream.iword( flagIndex() ) = 0;
return stream;
}
std::ostream&
operator<<( std::ostream& dest, MyClass const& object )
{
bool verbose = dest.iword( flagIndex() ) != 0;
// ...
return dest;
}
You can then write things like:
std::cerr << verbose << myObject;
Upvotes: 2
Reputation: 299950
You can add "flags" into the stream by actually encaspulating the stream itself.
struct Verbose {
explicit Verbose(std::ostream* s = 0): _stream(s) {}
std::ostream* _stream;
};
Verbose operator<<(std::ostream& out, Verbose) {
return Verbose(&out);
}
And then, you define a new operator for verbose output:
std::ostream& operator<<(Verbose v, MyClass const& mc) {
assert(v._stream);
std::ostream& out = *v._stream;
// ...
return out;
}
Usage:
std::cout << Verbose() << myInstance << "\n";
You'll note that Verbose
is not tied to the class, at all, and can be reused accross classes easily enough.
Note: if you want to, you could add an extra parameter to Verbose
to actually control the level of verbosity directly there.
Upvotes: 2
Reputation: 67157
You cannot add extra parameters to operator<<
, but you can easily define a custom printing function taking a verbosity parameter:
void dump(ostream& ostr, const myClass& obj, int verbosity = 1)
{
if (verbosity > 2)
ostr << "Very verbose!\n";
if (verbosity > 1)
ostr << "Verbose!\n";
if (verbosity > 0)
ostr << "Standard!\n";
ostr << "Minimal.\n";
}
Usage:
dump(cout, myobj); // Default
dump(cout, myobj, 0); // Minimal
dump(cout, myobj, 1); // Default
dump(cout, myobj, 2); // Verbose
dump(cout, myobj, 3); // Very verbose
You should also provide a stream operator forwarding to dump()
, using the default verbosity:
ostream& operator<<(ostream& ostr, const myClass& obj)
{
dump(ostr, obj);
return ostr;
}
If you want to follow that way, it might be a good idea to declare an enum
for the verbosity instead of using int
s:
enum Verbosity
{
MinimalOutput = 0,
StandardOutput = 1,
VerboseOutput = 2,
DebugOutput = 3
};
Upvotes: 1
Reputation: 490218
The standard way to modify the formatting of your item would be to implement a manipulator. It will typically do little more than set some flag(s). Your inserter will then modify its behavior based on the state of the flag(s).
Upvotes: 0