Skip to main content
added 9 characters in body
Source Link
Weijun Zhou
  • 5.6k
  • 2
  • 24
  • 44

In this case it's simpler to not derive from std::ostream unless your use case really requires you to. This allows you to completely bypass generating the output strings, if you create your own std::ostream then you can only override std::putc which will only be called just before the string is output.

You only need to implement operator<< which then optionally forwards to the actual std::ostream. From the user's point of view your logger class will behave exactly the same as std::ostream:

#include <iostream> struct verbosity { explicit verbosity(int unsigned verbosity) :_verbosity(verbosity) { } int unsigned _verbosity; }; class MessageFilterteringOStream { public: MessageFilterteringOStream(std::ostream& output) :_output(output) { } void setMessageThreshold(int unsigned threshold) { _threshold = threshold; } void setVerbosity(int unsigned verbosity) { _verbosity = verbosity; } template <typename T> MessageFilterteringOStream& operator<<(T&& value) { if (_threshold >= _verbosity) { _output << std::forward<T>(value); } return *this; } MessageFilterteringOStream& operator<<(verbosity value) { _verbosity = value._verbosity; return *this; } private: std::ostream& _output; int unsigned _threshold = 0; int unsigned _verbosity = 0; }; int main() { MessageFilterteringOStream _log(std::cout); _log.setMessageThreshold(100); _log << verbosity(200) << "Message with level 200 verbosity"; // NOT emitted _log << verbosity( 0) << "Message with level 0 verbosity"; // emitted } 

In this case it's simpler to not derive from std::ostream unless your use case really requires you to. This allows you to completely bypass generating the output strings, if you create your own std::ostream then you can only override std::putc which will only be called just before the string is output.

You only need to implement operator<< which then optionally forwards to the actual std::ostream. From the user's point of view your logger class will behave exactly the same as std::ostream:

#include <iostream> struct verbosity { verbosity(int unsigned verbosity) :_verbosity(verbosity) { } int unsigned _verbosity; }; class MessageFilterteringOStream { public: MessageFilterteringOStream(std::ostream& output) :_output(output) { } void setMessageThreshold(int unsigned threshold) { _threshold = threshold; } void setVerbosity(int unsigned verbosity) { _verbosity = verbosity; } template <typename T> MessageFilterteringOStream& operator<<(T&& value) { if (_threshold >= _verbosity) { _output << std::forward<T>(value); } return *this; } MessageFilterteringOStream& operator<<(verbosity value) { _verbosity = value._verbosity; return *this; } private: std::ostream& _output; int unsigned _threshold = 0; int unsigned _verbosity = 0; }; int main() { MessageFilterteringOStream _log(std::cout); _log.setMessageThreshold(100); _log << verbosity(200) << "Message with level 200 verbosity"; // NOT emitted _log << verbosity( 0) << "Message with level 0 verbosity"; // emitted } 

In this case it's simpler to not derive from std::ostream unless your use case really requires you to. This allows you to completely bypass generating the output strings, if you create your own std::ostream then you can only override std::putc which will only be called just before the string is output.

You only need to implement operator<< which then optionally forwards to the actual std::ostream. From the user's point of view your logger class will behave exactly the same as std::ostream:

#include <iostream> struct verbosity { explicit verbosity(int unsigned verbosity) :_verbosity(verbosity) { } int unsigned _verbosity; }; class MessageFilterteringOStream { public: MessageFilterteringOStream(std::ostream& output) :_output(output) { } void setMessageThreshold(int unsigned threshold) { _threshold = threshold; } void setVerbosity(int unsigned verbosity) { _verbosity = verbosity; } template <typename T> MessageFilterteringOStream& operator<<(T&& value) { if (_threshold >= _verbosity) { _output << std::forward<T>(value); } return *this; } MessageFilterteringOStream& operator<<(verbosity value) { _verbosity = value._verbosity; return *this; } private: std::ostream& _output; int unsigned _threshold = 0; int unsigned _verbosity = 0; }; int main() { MessageFilterteringOStream _log(std::cout); _log.setMessageThreshold(100); _log << verbosity(200) << "Message with level 200 verbosity"; // NOT emitted _log << verbosity( 0) << "Message with level 0 verbosity"; // emitted } 
Source Link
Alan Birtles
  • 38.3k
  • 4
  • 39
  • 73

In this case it's simpler to not derive from std::ostream unless your use case really requires you to. This allows you to completely bypass generating the output strings, if you create your own std::ostream then you can only override std::putc which will only be called just before the string is output.

You only need to implement operator<< which then optionally forwards to the actual std::ostream. From the user's point of view your logger class will behave exactly the same as std::ostream:

#include <iostream> struct verbosity { verbosity(int unsigned verbosity) :_verbosity(verbosity) { } int unsigned _verbosity; }; class MessageFilterteringOStream { public: MessageFilterteringOStream(std::ostream& output) :_output(output) { } void setMessageThreshold(int unsigned threshold) { _threshold = threshold; } void setVerbosity(int unsigned verbosity) { _verbosity = verbosity; } template <typename T> MessageFilterteringOStream& operator<<(T&& value) { if (_threshold >= _verbosity) { _output << std::forward<T>(value); } return *this; } MessageFilterteringOStream& operator<<(verbosity value) { _verbosity = value._verbosity; return *this; } private: std::ostream& _output; int unsigned _threshold = 0; int unsigned _verbosity = 0; }; int main() { MessageFilterteringOStream _log(std::cout); _log.setMessageThreshold(100); _log << verbosity(200) << "Message with level 200 verbosity"; // NOT emitted _log << verbosity( 0) << "Message with level 0 verbosity"; // emitted }