seattlecpp
seattlecpp

Reputation: 187

inserting objects onto ostreams

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

Answers (4)

James Kanze
James Kanze

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

Matthieu M.
Matthieu M.

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

Ferdinand Beyer
Ferdinand Beyer

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 ints:

enum Verbosity
{
    MinimalOutput = 0,
    StandardOutput = 1,
    VerboseOutput = 2,
    DebugOutput = 3
};

Upvotes: 1

Jerry Coffin
Jerry Coffin

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

Related Questions