Implementing a no-op std::ostream

c++, debugging, logging

Solution

To prevent the `operator<<()` invocations from doing formatting, you should know the streamtype at compile-time. This can be done either with macros or with templates.

My template solution follows.

class NullStream {
public:
    void setFile() { /* no-op */ }
    template<typename TPrintable>
    NullStream& operator<<(TPrintable const&)
    { return *this; } /* no-op */
}

template<class TErrorStream> // add TInfoStream etc
class Logger {
public:
    TErrorStream& errorStream() {
        return m_errorStream;
    }

private:
    TErrorStream m_errorStream;
};

//usage
int main() {
    Logger<std::ofstream> normal_logger; // does real output
    normal_logger.errorStream().open("out.txt");
    normal_logger.errorStream() << "My age is " << 19;

    Logger<NullStream> null_logger; // does zero output with zero overhead
    null_logger.errorStream().open("out.txt"); // no-op
    null_logger.errorStream() << "My age is " << 19; // no-op
}

Since you have to do this at compile-time, it is of course quite inflexible.

For example, you cannot decide the logging level at runtime from a configuration file.

Problem

I'm looking at making a logging class which has members like Info, Error etc that can configurably output to console, file, or to nowhere. For efficiency, I would like to avoid the overhead of formatting messages that are going to be thrown away (ie info messages when not running in a verbose mode). If I implement a custom std::streambuf that outputs to nowhere, I imagine that the std::ostream layer will still do all the formatting. Can anyone suggest a way to have a truly "null" std::ostream that avoids doing any work at all on the parameters passed to it with `<<`?

Original source