Skip to main content
AI Assist is now on Stack Overflow. Start a chat to get instant answers from across the network. Sign up to save and share your chats.
Fixed the Nullstream << operator so it does not crash on the second <<. Did not comment since author account is deleted.
Source Link
Alexis Wilke
  • 21.2k
  • 11
  • 111
  • 183

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.

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&) { /* 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.

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.

spelling fix part two (to get around 6-character requirement)
Source Link
Jesse
  • 8.8k
  • 7
  • 49
  • 57

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&) { /* 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.

 

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&) { /* 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.

 

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&) { /* 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.

spelling fix part two (to get around 6-character requirement)
Source Link

To perventprevent 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&) { /* 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.

 

To pervent 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&) { /* 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.

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&) { /* 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.

 
Source Link
Iraimbilanja
Iraimbilanja
Loading