views:

211

answers:

10

I need to have some lines of code "active" in debug mode only, and ignored in release mode. Is there a way to do something like this:

#include <iostream>
using namespace std;

#ifdef _TEST_
#define _cerr cerr
#else
#define _cerr // cerr
#endif

int main() {
   _cerr << "TEST message" << endl;
}

So that when _TEST_ is not defined, some lines are commented, or removed from the code. I know that comments are processed before the rest, so this code is wrong. But how can I get the behaviour I need without using #ifdefs explicitely?

+2  A: 

ifdefs are the way to go. How else would you know if the compiler is in release vs debug mode? When else besides during the preprocessing stage would that be communicated? At what other stage could you decide to remove/add code (besides during template generation). Hey maybe we can use template generation... but you still have to key off the ifdef somehow to control your template.

Maybe there's a really slick way to do this that I'm not thinking of, but everyone knows/uses ifdefs for this purpose. If you throw them a curveball its only going to drastically increase the human cost of maintaining your code.

Stick with ifdefs.

Doug T.
+8  A: 

You can use a macro for this:

#ifdef _TEST_
#define DEBUG_ONLY(x) x;
#else
#define DEBUG_ONLY(x)
#endif

int main() {
    DEBUG_ONLY(cerr << "TEST message" << endl)
}
reko_t
useful macro +1
Doug T.
not adding the semicolon in the macro makes your code more C++ like (forces user to add `;` after `DEBUG_ONLY` clause)
xtofl
The only problem I see with this macro is that you are limited to one statement. I personnally prefer a `do { x; } while(0)` clause to allow multiple statements in the macro (even though some compilers complain about the `while(0)` part... :/)
Matthieu M.
A: 
int main() {
#ifdef _TEST_
   _cerr << "TEST message" << endl;
#endif
}
Alan Christensen
+4  A: 

Use this:

#ifdef _TEST_
#define DEBUG_TEST(x) x
#else
#define DEBUG_TEST(x)
#endif

int main() {
    DEBUG_TEST(_cerr << "TEST message" << endl);
}
Shachar
A: 

No. Absolutely, no.

Try a variation on this:

#ifdef _TEST_
    ostream& _cerr = cerr;
#else
    ostringstream _cerr;
#endif

(Basically you would want a stream which just discards its input.)

Justice
First of all, using a global name with an underscore prefix is reserved for the implementation, I believe. Second of all, a stream that discards its input is not going to prevent the arguments from being evaluated, making this approach useless in any performance-sensitive context.
Tom
+1  A: 

This here basically does what you are asking for:

#ifdef _TEST_
#define _cerr  cerr
#else
#define _cerr  if (1) {} else cerr
#endif

But don't be surprised if you for example get compiler warnings about ambiguous else if you write something like this:

if (something)
  _cerr << "Why?" << std::endl;

You should always be aware of the fact that this _cerr is in fact a non-trivial macro.

sth
+1  A: 

Defining _cerr to nothing will fail the compilation. You could instead define a macro that you exclude while in release mode.

For example:

#ifdef _TEST_
#define LOG_ERROR(log) cerr << log << endl;
#else
#define LOG_ERROR(log) 
#endif

Then in your code:

int main() {
   LOG_ERROR("TEST message");
}
Eric Fortin
He wasn't trying to define it to nothing. He was hoping the comment slashes would be included in the macro expansion, so the result would be a commented-out logging line.
Rob Kennedy
+5  A: 

If what you are after is debug logging which is removed in release builds, you can do something like:

#ifdef _TEST_
#define LOG(x) (cerr << x << endl)
#else
#define LOG(x)
#endif

...

int main() {
    LOG("TEST message");
}
Rob Charlton
A: 

A nicer solution for the "no logging in release" is the following class:

class NullStream {
   template<typename T> NullStream& operator<< const(T&) { }
};

Use:

#ifdef DEBUG
#define CERR std::cerr
#else
#define CERR NullStream()
#endif
MSalters
Not nicer: the arguments will be evaluated... even if this is useless!
Matthieu M.
MSalters
A: 

Create your own NULL stream.

#include <iostream>

class NullStream    {};
template<typename T>
NullStream& operator <<(NullStream& n,T const& data)                        {return n;}
NullStream& operator <<(NullStream& n,std::ostream& (*)(std::ostream&))     {return n;}

#ifdef  _TEST_
#define myerr       std::cerr
#else
NullStream  myerrstream;
#define myerr       myerrstream
#endif

int main()
{
    myerr << "Hi" << std::endl;;
    myerr << std::endl;;
}
Martin York