3

I'm writing a logging class at the moment. The Logger works with streams and also prints the object which is logging at the moment. Here is the macro:

#define OBJLOG(DL, what) DL <= this->Logger->getDebugLevel() ? *this->Logger << DL << "[" << this->Name << "]: "<< what << std::endl : this->Logger->doNothing();

The pseudo code Variant for better overview:

#define OBJLOG(debuglevel, what) debuglevel <= logger.debuglevel ? logger.log(what) : logger.doNothing()

Is there any way to get around the doNothing function call, like doing nothing at all?

Jason Aller
  • 3,541
  • 28
  • 38
  • 38
roohan
  • 731
  • 3
  • 8
  • 15

3 Answers3

4
#define OBJLOG(DL, what) do { if(DL <= this->Logger->getDebugLevel()) *this->Logger << DL << "[" << this->Name << "]: "<< what << std::endl; } while(0)

See Why use apparently meaningless do-while and if-else statements in macros? for an explanation. (The do {} while(0) isn't strictly necessary here, but I would prefer not to leak an ostream.)

Also, you should always wrap macro argument uses in parentheses, like:

#define OBJLOG(DL, what) do { if((DL) <= this->Logger->getDebugLevel()) *this->Logger << (DL) << "[" << this->Name << "]: "<< (what) << std::endl; } while(0)

Finally, you should move this code into a function and call that in your macro (if you really insist on using a macro) to avoid evaluating your macro arguments more than once.

Community
  • 1
  • 1
Electro
  • 2,994
  • 5
  • 26
  • 32
  • Hi, and thank you for your answer. I just dont get the last part you wrote about moving it into a function call. But ill give it try now and see how to get it working. – roohan May 02 '12 at 15:42
  • You might *not* want parentheses around the `what` parameter; they change the possible syntax of the macro call. Without parentheses, you can call `OBJLOG(0, "x: " << x << "; y: " << y)`. With parentheses, you get a syntax error in the macro expansion (because you can't shift char arrays). – Rob Kennedy May 02 '12 at 15:47
  • If macro arguments get expanded multiple times, you had better hope (i.e. don't count on it) your expressions have no side effects. E.g. hypothetically doing `OBJLOG(--i ? DEBUG : WARN, "foo")` would decrement `i` twice. (It's a contrived example, but beware of that when writing macros.) – Electro May 02 '12 at 15:47
  • @RobKennedy: It had occurred to me, but better safe than sorry, I guess. – Electro May 02 '12 at 15:49
1
  1. Have your logger.log() function return a boolean.

  2. Connect your predicates with an and like this: debuglevel <= logger.debuglevel && logger.log

That should do the trick.

Anon Mail
  • 4,660
  • 1
  • 18
  • 21
  • Using the first code variant, your first step isn't even necessary. The `Logger` object is evidently a stream pointer, and streams can be used in bool expressions implicitly: `(DL <= this->Logger->getDebugLevel() && (*this->Logger << ... << what << std::endl))`. – Rob Kennedy May 02 '12 at 15:55
  • @Rob the logger does have a stream operator but I assumed it was a user defined class that most likely contains a stream as one of it's members. My own implementation does this so I had to add the bool conversion operator. Just an assumption though. – Anon Mail May 02 '12 at 18:44
0

If you want an expression that does nothing, try (void)0.

Derek Ledbetter
  • 4,675
  • 3
  • 20
  • 18