7

I am writing a logger. If disabled, this is the code which defines the LOG macro:

#ifdef NO_LOG

#include <ostream>

struct nullstream : std::ostream {
    nullstream() : std::ios(0), std::ostream(0) {}
};

static nullstream logstream;

#define LOG if(0) logstream

#endif

LOG << "Log message " << 123 << std::endl;

It works correctly. The compiler should completely remove the code related to the LOG macro.

However I would like to avoid the inclusion of ostream and define the logstream object as something really "light", possibly null.

Thank you!

Pietro M
  • 1,905
  • 3
  • 20
  • 24

2 Answers2

12
// We still need a forward declaration of 'ostream' in order to
// swallow templated manipulators such as 'endl'.
#include <iosfwd>

struct nullstream {};

// Swallow all types
template <typename T>
nullstream & operator<<(nullstream & s, T const &) {return s;}

// Swallow manipulator templates
nullstream & operator<<(nullstream & s, std::ostream &(std::ostream&)) {return s;}

static nullstream logstream;

#define LOG if(0) logstream

// Example (including "iostream" so we can test the behaviour with "endl").
#include <iostream>

int main()
{
    LOG << "Log message " << 123 << std::endl;
}
Mike Seymour
  • 249,747
  • 28
  • 448
  • 644
  • It works, but is it possible to avoid the inclusion of iostream? E.g., is it possible to use something else instead of std::endl? – Pietro M Dec 08 '11 at 15:57
  • @Pietro: that's only needed for the example, for `std::endl`. `nullstream` itself doesn't need that, just `` (forward declarations of the `` types). – Mike Seymour Dec 08 '11 at 16:00
  • @Pietro Often it is possible to use '\n' instead of std::endl. – UncleBens Dec 08 '11 at 16:07
  • @Mike: in this case, would '\0' or '\n' have the same effect as std::endl? They would not require the inclusion of ostream. – Pietro M Dec 08 '11 at 16:08
  • '\n' is the newline character, std::endl outputs a newline and flushes the output buffer. AFAIK, it is not necessary ever to flush a std::cerr, and not sure about std::clog. – UncleBens Dec 08 '11 at 16:11
  • @UncleBens: I am writing on a file. Can I make a file behave like std::cerr? – Pietro M Dec 08 '11 at 16:18
  • @MikeSeymour: I checked: '\n' does not flush the string, at least when the output is on a file. – Pietro M Dec 08 '11 at 16:45
5

Why not implement the entire thing from scratch:

struct nullstream { };

template <typename T>
nullstream & operator<<(nullstream & o, T const & x) { return o; }

static nullstream logstream;
Kerrek SB
  • 464,522
  • 92
  • 875
  • 1,084
  • 2
    That should be `nullstream` instead of `std::ostream`? – sth Dec 08 '11 at 15:32
  • 2
    Do you mean `nullstream & operator<<(nullstream & o, T const & x)`? And it won't work with `endl`. – fefe Dec 08 '11 at 15:32
  • @fefe: you are right; endl seems to be the only problem, now. Is it possible to terminate a stream in another way. I really would like to avoid the inclusion of ostream if I do not need logging... – Pietro M Dec 08 '11 at 16:03
  • @PietroM if you use `endl`, then maybe you have to include `ostream`, as `endl` is in fact a (template) function taking `ostream&` as parameter, and `endl` is defined in . There can be an ugly solution for this though, which is to `#define endl 0`. This will break normal use of `endl`, but if you don't have `ostream`, I think there will be no normal use of `endl`. – fefe Dec 08 '11 at 16:15
  • @fefe: #define endl 0 is a bit too extreme. I may need to produce normal output even if logging is disabled... – Pietro M Dec 08 '11 at 16:24
  • @sth: D'oh, yes! Fixed, thank you! About `endl`... if we include ``, that's very cheap; can we define a suitable overload to accommodate `endl`? – Kerrek SB Dec 08 '11 at 16:47
  • inline nullstream& ends(nullstream& s) { return s; } – Pietro M Dec 08 '11 at 17:21