views:

676

answers:

4

Hi

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?

+2  A: 

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
+2  A: 

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.

anon
@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
@Konrad Suprisingly enough, I do know this. Consider it one of my little coding foibles.
anon
+5  A: 

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
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.
CodeMedic
@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
@Konrad Rudolph: It looks cool, but won't constant writing to dummy cause some kind of buffer overflow?
zbigh
This actually caused segmentation fault - I had to use ofstream and redirect it to /dev/null
zbigh
@Konrad Doesn't compile with g++. What compiler are you using?
anon
Frerich Raabe
g++ - version 2.91.66, linux ( 2.4.29 kernel ) - it's old cause it's an embedded system we use.
zbigh
@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
@Frerich: thanks for the pointer. I’ve done something similar.
Konrad Rudolph
A: 

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