One can remove all calls to printf()
using #define printf
. What if I have a lot of debug prints like std::cout << x << endl;
? How can I quickly switch off cout <<
statements in a single file using preprocessor?
NullStream can be a good solution if you are looking for something quick that removes debug statements. However I would recommend creating your own class for debugging, that can be expanded as needed when more debug functionality is required:
class MyDebug
{
std::ostream & stream;
public:
MyDebug(std::ostream & s) : stream(s) {}
#ifdef NDEBUG
template<typename T>
MyDebug & operator<<(T& item)
{
stream << item;
return *this;
}
#else
template<typename T>
MyDebug & operator<<(T&)
{
return *this;
}
#endif
};
This is a simple setup that can do what you want initially, plus it has the added benefit of letting you add functionality such as debug levels etc..
Update: Now since manipulators are implemented as functions, if you want to accept manipulators as well (endl) you can add:
MyDebug & operator<<(std::ostream & (*pf)(std::ostream&))
{
stream << pf;
return *this;
}
And for all manipulator types (So that you don't have to overload for all manipulator types):
template<typename R, typename P>
MyDebug & operator<<(R & (*pf)(P &))
{
stream << pf;
return *this;
}
Be careful with this last one, because that will also accept regular functions pointers.
As "unwind" already said, the quick solution is a do-nothing stream. There are better implementations though:
class NullStream {
public:
NullStream() { }
template<typename T> NullStream& operator<<(T const&) { return *this; }
};
You still have a slight issue with std::cout
since that's a sequence of three tokens, and you really don't want to redefine std
or cout
individually. A simple solution is
#ifdef NDEBUG
#define COUT std::cout
#else
#define COUT NullStream()
#endif
COUT << "Hello, world" << std::endl;
As a general principle logging to stdout should be avoided - far better to log to a logfile, and then you can use standard configuration tools to change log levels, or turn it off altogether.
Just my $0.02.....
Substitute your debug output statements with something like this:
IFDBG(cout << result << endl);
Then you can define macros accordingly:
#ifdef DEBUG
# define IFDBG(x) x
#else
# define IFDBG(x)
#endif
IFDBG(cout << foo(x,y) << std::endl);
. The comma is going to break the macro. –
Twicetold Define this macro :
#ifdef DEBUG
#define MY_LOG std::cout
#else
#define MY_LOG if(false) std::cout
#endif
This macro advantage is in compiler optimization
If expressions placed inside those IFs are constant and determinable at the time of compilation, then you may be almost sure that the compiler has already removed them off the code for you... https://mcmap.net/q/375962/-c-attempt-to-optimize-code-by-replacing-tests
NullStream can be a good solution if you are looking for something quick that removes debug statements. However I would recommend creating your own class for debugging, that can be expanded as needed when more debug functionality is required:
class MyDebug
{
std::ostream & stream;
public:
MyDebug(std::ostream & s) : stream(s) {}
#ifdef NDEBUG
template<typename T>
MyDebug & operator<<(T& item)
{
stream << item;
return *this;
}
#else
template<typename T>
MyDebug & operator<<(T&)
{
return *this;
}
#endif
};
This is a simple setup that can do what you want initially, plus it has the added benefit of letting you add functionality such as debug levels etc..
Update: Now since manipulators are implemented as functions, if you want to accept manipulators as well (endl) you can add:
MyDebug & operator<<(std::ostream & (*pf)(std::ostream&))
{
stream << pf;
return *this;
}
And for all manipulator types (So that you don't have to overload for all manipulator types):
template<typename R, typename P>
MyDebug & operator<<(R & (*pf)(P &))
{
stream << pf;
return *this;
}
Be careful with this last one, because that will also accept regular functions pointers.
You can probably do a preprocessor hack that defines a new stream-like class, with an instance named cerr
, that just does nothing. If you're really lucky, the compiler will see that the function does nothing, and optimize the calls to operator<<()
out.
Something like
class NullStream
{
public:
NullStream();
NullStream& operator<<(const std::string& text) { return *this; }
// And operators for other types, too
}
static NullStream cerr;
This is quite the hack though, it's (far) better to go through your source and add proper support for logging.
Defining a macro that replaces cout
is not something you should upload to your VCS, but if you just do it temporarily during debugging, I think it serves its place. So you can just replace cout
by ostream(0)
like
#ifdef NDEBUG
#define cout ostream(0).flush()
#endif
This way, it works with both std::cout
and plain cout
, and ostream
is available when including <iostream>
. Writing into a ostream(0)
is a no-op. The flush
function call is done so that you get a non-const reference to it (so it also binds to non-member operator<<
that's used for outputting std::string
and others). As its type is ostream
, it should behave exactly like cout
.
© 2022 - 2024 — McMap. All rights reserved.