4

I have some code that is sprinkled with constructs like this

if(debug) {
    Output << "f1: " << f1() << "\n";
}

Now what I want to do is write a stream class Debug where I could write it like this

Debug << "f1: " << f1() << "\n";

If some global flag is set then this would generate output, otherwise not.

Now: this can be quite easily done by making Debug return a stream that goes to /dev/null which would swallow the output. The problem is that f1() still gets evaluated (and 'rendered' into a textual representation which might be even more expensive) which might be quite bad for the performance.

Now my question: is there any trick that allows the skipping of the 'evaluation' of

"f1: " << f1() << "\n"

completely if Debug decides that no output should be done? Similar to the short circuiting that C++ does for f() && g() where g() is not evaluated if f()is false (I seriously considered writing a stream class that uses && as the output operator but from what I read short-circuiting is not done for overloaded operator&&)

bgschaid
  • 243
  • 1
  • 5
  • [This related question](http://stackoverflow.com/questions/11826554/standard-no-op-output-stream) from earlier today could have the solution. – juanchopanza Aug 06 '12 at 17:23
  • @juanchopanza: Those questions still (possibly) evaluate the arguments. I don't think this can be done as asked, unless you switch the format to something like `DEBUGOUT("f1: " << f1() << "\n");` – Mooing Duck Aug 06 '12 at 17:30
  • @MooingDuck true. They only avoid the streaming. – juanchopanza Aug 06 '12 at 17:31
  • this SO looks similar: http://stackoverflow.com/questions/5035840/lazy-evaluation-with-ostream-c-operators – marcinj Aug 06 '12 at 17:34
  • @MooingDuck: Except the one using the [evil macro](http://stackoverflow.com/a/11826787/204847). – Mike Seymour Aug 06 '12 at 17:35

3 Answers3

5

What you can do is define this macro:

#define Debug_Stream \
if(!debug); else Output

This would make this:

Debug_Stream << "f1: " << f1() << "\n";

become equivalent to this:

if(debug) {
    Output << "f1: " << f1() << "\n";
}

But literally (plus whitespace for readability)

if(!debug);
else
    Output << "f1: " << f1() << "\n";
Eric Finn
  • 8,629
  • 3
  • 33
  • 42
4

If you're not adverse to a macro, and are willing to accept the syntax:

Debug( "f1: " << f() << '\n' );

it's pretty simple: just define something like:

#define Debug( x ) debug != NULL && *debug << x;

It's somewhat dangerous, however, since you can't take the usual precaution of putting the argument in parentheses. (On the other hand, I've seen it used in a number of applications, without problems.) The macro approach has the added advantage of allowing you to insert __FILE__ and __LINE__ automatically, if you want. Or to conditionally suppress all of the code completely, by defining the macro to be nothing.

James Kanze
  • 150,581
  • 18
  • 184
  • 329
2

I think you can do this by creating a delayed-evaluator that wraps expensive function calls. Your stream would know for the delayed evaluator type it needs to call the referenced function but otherwise it no-ops it, preventing the expensive call. The no-debug stream knows that for your proxy evaluator objects to just skip the evaluation completely.

For example a call might look like:

Debug << "123" << delay(f()) << "456" << std::endl;

This does involve remembering to invoke the delay in your debug lines. It does avoid the need for macros which may or may not be a key issue in your case.

Mark B
  • 95,107
  • 10
  • 109
  • 188