I'm adding a bit amount of tracing and debugging code into a class that I'm refactoring.
I have a Trace
object which has some filtering properties and methods bool CanTrace(Level, , TracePropertyList = no_additional_properties)
and bool Trace(Level, string, TracePropertyList = no_additional_properties)
.
There are already many places in the code where this trace object is used, and the string argument to the Trace
method is usually some expression that I would like to avoid evaluating if I'm not going to end up outputting tracing info.
Repeating the chunk of code
if(trace.CanTrace(LEVEL_INFO, some_props))
trace.Trace(LEVEL_INFO, consume_time().to_str(), some_props);
is ugly, and I'd like something shorter.
I was thinking about the macros
#define TRACE_WITH_PROPS(LEVEL,STRING,PROPS) //...
and
#define TRACE(LEVEL,STRING) //...
Is there a better way to do this? Possibly with templates or C++11? I don't like hiding things from the compiler with defines, and I'm doing my best to remove some macros elsewhere in this codebase.
In C++11, you can use closure. You'd have something like:
trace.Trace(LEVEL_INFO, [&](){ return format("x is %i") % ExpensiveWayToGetX(y, z); }, some_props);
In C++03, you can use the boost.lambda hack for similar effect.
However, having a macro wrapping the if(trace.CanTrace(...)) trace.Trace(...)
is still slightly more efficient, because it doesn't even initialize the object with all the references the closure will need if tracing is not on. I suggest combining the macro with the stream interface, so you'd have
#define TRACE(level, some_props) \
if(!trace.CanTrace(level, some_props)) 0; \
else trace.Trace(level, some_props)
and call it like
TRACE(LEVEL_INFO, some_props) << "x is " << ExpensiveWayToGetX(y, z);
or define operator()
instead of operator<<
and for printf-style formatting:
TRACE(LEVEL_INFO, some_props)("x is %i", ExpensiveWayToGetX(y, z));
The if not enabled, than 0, else actually trace is there so that it does not eat the else if you ever write:
if(IsSomethingWrong())
TRACE(LEVEL_WARNING, some_props) << WhatIsWrong() << " is wrong";
else
DoSomething();
(without else in the macro, the else after it would go to the if inside the macro, but with that else, it will parse correctly)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With