3

I thought of a small debug inline function in C++:

void inline debug( int debug_level, ostream& out ) {
    if ( debug_level <= verbosity ) {
        out.flush();
    }
    else {
        ostream tmp;
        tmp << out;
    }
}

This is an example of how I wanted to use it:

_debug( 7, cout << "Something something" << someint << endl );

However it does not work in the way I planned - I wanted it to print the message only if the verbosity level is higher or equal then the debug level passed to function, but it seems it prints everytime regardless of the debug level, so data stays in the cout buffer. By now I think this function's not the best idea I've had lately, but still I want to know if there's a way to clear the buffer associated with cout, cerr etc. Is it possible to get this kind of function to work properly?

zbigh
  • 457
  • 2
  • 9
  • 16
  • If you want to go Konrad's route, using the idea of a null stream, take a look at this question http://stackoverflow.com/questions/760301/implementing-a-no-op-stdostream –  Feb 03 '10 at 13:26
  • Oh, I just don't like oldschool-C macros, I prefer the C++ way ;) – zbigh Feb 03 '10 at 13:37
  • Macros are about as avoidable in C++ as they are in C, I'm afraid. –  Feb 03 '10 at 13:52
  • Yep, use macro's judiciously, but for logging, they can be nice to also log the function/file/line-number. Like it or not, they still have their place. – stefaanv Feb 03 '10 at 16:23

4 Answers4

6

Either using a macro as shown above, or like this:

struct nullstream : ostream {
    nullstream() : ostream(0) { }
};

ostream& dout(int debug_level, ostream& out = cerr) {
    static nullstream dummy;
    return debug_level <= verbosity ? dummy : out;
}

// …

dout(level) << "foo" << endl;
dout(level, cout) << "IMPORTANT" << endl;

(Using endl also triggers flushing, no need to flush manually!)

Konrad Rudolph
  • 530,221
  • 131
  • 937
  • 1,214
  • Only trouble is the unnecessary construction of a stream buffer. It is nicer to avoid the stream buffer construction; considering that logging might be something that you do more often than any other operation in a headless process. – ϹοδεMεδιϲ Feb 03 '10 at 12:19
  • @CodeMedic: that’s why the stream is `static`: it’s constructed only **once**, in all the program. That is practically no overhead and you can call this method as often as you like. – Konrad Rudolph Feb 03 '10 at 12:30
  • @Konrad Rudolph: It looks cool, but won't constant writing to dummy cause some kind of buffer overflow? – zbigh Feb 03 '10 at 12:54
  • This actually caused segmentation fault - I had to use ofstream and redirect it to /dev/null – zbigh Feb 03 '10 at 13:08
  • @Konrad Doesn't compile with g++. What compiler are you using? –  Feb 03 '10 at 13:21
  • 1
    I use the same technique in my code; however, it won't work as shown above since the (only) ostream constructor takes a streambuf* argument. Hence, I usually do `struct nullbuf : streambuf {}; static nullbuf buf;` and then pass &buf when constructing the returned ostream object. – Frerich Raabe Feb 03 '10 at 13:25
  • g++ - version 2.91.66, linux ( 2.4.29 kernel ) - it's old cause it's an embedded system we use. – zbigh Feb 03 '10 at 13:30
  • @Neil: All right, I’ve added a `nullstream` class – but I need to say that the code compiled warning-free even before, on g++ 4.4.2 on strictest warning level (`-Wall -Wextra`) with `-pedantic`. That said, I’m not very good with the C++ iostream library so please test again. – Konrad Rudolph Feb 03 '10 at 15:20
  • @Frerich: thanks for the pointer. I’ve done something similar. – Konrad Rudolph Feb 03 '10 at 15:21
2

I'm not sure whether it can be done with functions/templates. I know code with macro's (your log-message and stream is separated):

#define LOG(svrty, out, msg)\
do {\
  if (svrty >= debug_level) out << msg;\
} while(0)

Although this works, I am interested in better solutions. Remark that you should let the configuration and debug-level decide where to log to.

stefaanv
  • 14,072
  • 2
  • 31
  • 53
2

It will always print the message, because function parameters are evaluated before the body of the function is entered. You can get the effect I think you want with a macro, as macro parameters are only evaluated when they are used:

#define DOUT( level, expr )   \
   if ( level >= verbosity )  {     \
      expr << endl;          \
  }

In use:

 DOUT( 42, cout << "The value is " << something );

If you are picky, you will want to wrap this in a do/while loop - personally, I never bother doing so.

  • @Neil: well, you really *should* bother because now your usage is wrong: you put a redundant semicolon behind it. Not think what happens if this is inside an `if` and the next statement is an `else`. – Konrad Rudolph Feb 03 '10 at 12:14
  • @Konrad Suprisingly enough, I do know this. Consider it one of my little coding foibles. –  Feb 03 '10 at 12:15
0

Is the debug level run time configureable?
If not you may use templates and template specialization:

template <int DebugLevel, int Verbosity>
ostream &debug(ostream &out);

template<>
ostream &debug<7, 5>(ostream &out) { /* do stuff */ }

That way if you don't want to output anything, just return the dummy ostream like Konrad Rudolph suggested.

the_drow
  • 18,571
  • 25
  • 126
  • 193