How to trigger action on end-of-statement? - c++

Suppose that I want to create a stream that would perform an action at the end of the statement, so that
myStream << "Hello, " << "World!";
would print "Hello, World!\n" in one shot. Not "Hello, \nWorld!\n" and not "Hello, World!", but "Hello, World\n", as if ; would trigger appending \n and flushing the buffers.
The rationale for that is a stream class that writes to both stdout and a logfile, with the logfile entries having certain prefixes and suffixes.
For example, if my target was HTML I would want this code:
myStream << "Hello, " << "World!";
myStream << "Good bye, " << "cruel World!";
to print like this:
<p>Hello, World!</p>
<p>Good bye, cruel World!</p>
and not like this:
<p>Hello, </p><p>World!</p>
<p>Good bye, </p><p>cruel World!</p>
Now, if I implement LogStream sort of like this:
LogStream & LogStream::operator<<( const std::string & text );
I won't be able to distinguish between << in the middle of the statements from the ones in the beginning/ending of the statements.
If I implement LogStream sort of like this:
LogStream LogStream::operator<<( const std::string & text );
and try to massage the input in the destructor I would get multiple destructors at once at the end of the block.
Finally, I can implement this my requiring endl at the end of each statement, but I'd rather not bother the caller with the necessity to do so.
Thus the question: how one implements such a stream in a caller-transparent fashion?

I implemented something like this once for a custom logging system. I created a class that buffered input and then its destructor flushed the buffer to my log file.
For example:
#include <iostream>
#include <sstream>
#include <string>
class LogStream
{
private:
std::stringstream m_ss;
void flush()
{
const std::string &s = m_ss.str();
if (s.length() > 0)
{
std::cout << s << std::endl;
logfile << "<p>" << s << "</p>" << std::endl;
}
}
public:
LogStream() {}
~LogStream()
{
flush();
}
template <typename T>
LogStream& operator<<(const T &t)
{
m_ss << t;
return *this;
}
template <typename T>
LogStream& operator<<( std::ostream& (*fp)(std::ostream&) )
{
// TODO: if fp is std::endl, write to log and reset m_ss
fp(m_ss);
return *this;
}
void WriteToLogAndReset()
{
flush();
m_ss.str(std::string());
m_ss.clear();
}
};
For single statements that flush on the final ;, each message would use a new instance of the class:
LogStream() << "Hello, " << "World!";
LogStream() << "Good bye, " << "cruel World!";
To allow multiple statements to write to a single message, create the object and do not let it go out of scope until the last statement is done:
{
LogStream myStream;
myStream << "Hello, ";
myStream << "World!";
}
{
LogStream myStream;
myStream << "Good bye, ";
myStream << "cruel World!";
}
To reuse an existing instance for multiple messages, tell it to flush and reset in between each message:
{
LogStream myStream;
myStream << "Hello, " << "World!";
myStream.WriteToLogAndReset();
myStream << "Good bye, " << "cruel World!";
}
I like this approach because it gives the caller more flexibility in deciding when each message is ready to be written to the log file. For instance, I use this to send multiple values to a single log message where those values are obtained from decision-making code branches. This way, I can stream some values, make some decisions, stream some more values, etc and then send the completed message to the log.

The line:
myStream << "Hello, " << "World!";
Is actually multiple statements. It's equivalent to:
ostream& result = myStream << "Hello, ";
result << "World!";
There are some tricks to do what you want by returning an unnamed temporary object (which are destroyed at the end of the full-expression). Here is some example code.

I have a little code that I haven't gotten round to doing anything constructive with that I think is doing what you're asking.
It works by using a proxy class (log_buffer) to build up the string in a std::stringstream object. At the end of the expression the log_buffer proxy object calls the main log_writer
object to process the whole line contained in the std::stringstream.
class log_writer
{
// ultimate destination
std::ostream* sink = nullptr;
// proxy class to do the << << << chaining
struct log_buffer
{
log_writer* lw;
std::stringstream ss;
void swap(log_buffer& lb)
{
if(&lb !=this)
{
std::swap(lw, lb.lw);
std::swap(ss, lb.ss);
}
}
log_buffer(log_writer& lw): lw(&lw) {}
log_buffer(log_buffer&& lb): lw(lb.lw), ss(std::move(lb.ss)) { lb.lw = nullptr; }
log_buffer(log_buffer const&) = delete;
log_buffer& operator=(log_buffer&& lb)
{
swap(lb);
return *this;
}
log_buffer& operator=(log_buffer const&) = delete;
// update the log_writer after the last call to << << <<
~log_buffer() { if(lw) lw->add_line(ss); }
template<typename DataType>
log_buffer operator<<(DataType const& t)
{
ss << t;
return std::move(*this);
}
};
void swap(log_writer& lw)
{
if(&lw != this)
{
std::swap(sink, lw.sink);
}
}
public:
log_writer(std::ostream& sink): sink(&sink) {}
log_writer(log_writer&& lw): sink(lw.sink) { lw.sink = nullptr; }
log_writer(log_writer const&) = delete;
log_writer& operator=(log_writer&& lw)
{
swap(lw);
return *this;
}
log_writer& operator=(log_writer const&) = delete;
// output the final line
void add_line(std::stringstream& ss)
{
// Do any special line formatting here
if(sink) (*sink) << ss.str() << std::endl;
}
template<typename DataType>
struct log_buffer operator<<(DataType const& data)
{
return std::move(log_buffer(*this) << data);
}
};
int main()
{
std::ofstream ofs("test.log");
log_writer lw1(ofs);
log_writer lw2(std::cout);
lw1 << "lw1 " << 2.93 << " A";
lw2 << "lw2 " << 3.14 << " B";
std::swap(lw1, lw2);
lw1 << "lw1 " << 2.93 << " C";
lw2 << "lw2 " << 3.14 << " D";
}

Related

Does the stream operator exist for class member functions?

I included the logger from boost. I'm pretty pleased how it works. Just for simplicity and the reason I don't want to use makros to often in my code, I wrap it in a class.
I now wonder if I could use the streaming operator << to write on a member function.
code
class LogWrapper{
...
//debug function
//info function
...
}
void main() {
LogWrapper log;
log.debug() << "some debug msg"; // does this exist?
log.info() << "some info msg";
}
output
[some_timestamp][debug] some debug msg
[some_timestamp][info] some info msg
Is this possible in a good practice, or is it entirely bad style?
It can be done easily like this:
#include <iostream>
class A {
public:
std::ostream &debug() const {
std::cerr << "[timestamp]" << "[DEBUG]";
return std::cerr;
}
};
int main()
{
A a;
a.debug() << "Test";
}
But the important question here is: Should we implement it in this way? In my opinion, NO!
Because you are thinking that the User of the class will print the logs like this:
int main()
{
A a;
a.debug() << "Test" << std::endl;
a.debug() << "Test2" << std::endl;
}
Output:
[timestamp][DEBUG]Test
[timestamp][DEBUG]Test2
But what if User chooses this way:
int main()
{
A a;
auto &out = a.debug();
out << "Test" << std::endl;
out << "Test2" << std::endl;
}
Output:
[timestamp][DEBUG]Test
Test2
I would highly recommend not to return stream object. You should use member functions for this purpose.
#include <iostream>
class A {
public:
static void debug(const std::string &log) {
std::cerr << "[timestamp]" << "[DEBUG]" << log << std::endl;
}
};
int main()
{
A::debug("Test 1");
A::debug("Test 2");
}
Output:
[timestamp][DEBUG]Test 1
[timestamp][DEBUG]Test 2

Detect end of line before next one

I don't know how to "buffer" a line of input (and perform some operations on that line, e.g. insert a newline at the end) before the next one in the following code:
#include <iostream>
class Test {
public:
template<class T>
Test& operator<< (T&& anything) {
std::cout << anything;
return *this;
}
};
int main() {
Test myobj;
myobj << "hello" << "this is cool";
// How to insert a newline here?
myobj << "but" << "this is NOT cool";
}
I'd like to be able to detect when the line
myobj << "hello" << "this is cool";
has completed before the next one is executed.
`"\n"`
do it for you as shown below:
int main() {
Test myobj;
myobj<< "hello" << "this is cool<<"\n"";
// How to insert a newline here?
myobj << "but" << "this is NOT cool";
}
Or otherwise you use std::endl as follows
myobj << "hello" << "this is cool<<std::endl;
You can detect it in its destructor. Create a log() helper function that returns a temporary. At the end of the full expression its destructor will run:
class Test {
public:
template<class T>
Test& operator<< (T&& anything) {...}
~Test() { std::cout << std::endl; }
};
Test log() { return Test(); }
// ...
log() << "hello" << "this is cool"; // destructor inserts a newline here
log() << "but" << "this is NOT cool"; // here too

Cant express myself in c++ other than with a macro

I have a macro that does exactly what I want it to do:
#define LOG(x)\
do { if (!cpp::app::g_app) {\
ASSERT("CANNOT LOG IF THERE IS NO CPP APP OBJECT" == 0);\
}\
else \
{ \
std::stringstream s; s << cpp::timing::currentDateTime(); s << '\t'; s << x << std::endl; \
*cpp::app::g_app << s.str(); \
cpp::app::g_app->flush(true);\
} \
} while(0)
#endif
Its really nice, because I can:
LOG("On first log line " << 0 << "Still on first log line")
..and a newline is inserted once the LOG macro is done.
Output looks like:
<date / time> On First log line 0 Still on first log line
... subsequent lines here
My question is how to overload << operator on my logging class to do the same?
If I simply overload << operator and return *this (where my logging case can be converted to ostream) then if I do:
mylogger << "First line " << "Still on first line";
then the output is something like:
<date and time> First line
<date and time> Still on first line.
So, I want to emulate the macro behaviour with the << operator. I want a newline automatically when the whole chain of << operations is complete, just like in the macro. But, since macros are evil, I'd rather convert it to a proper function.
Is this achievable?
Edit: Matt's idea about a helper class is quite nice. Based on his suggestion, I made the following disposable helper class:
class log
{
public:
log() :
m_stream(cpp::app::g_app->stream()){
}
template <typename T>
log& operator << (const T& t)
{
m_ss << t;
return *this;
}
virtual ~log(){
m_stream << cpp::timing::currentDateTime() << "\t" << m_ss.str() << "\r\n";
m_stream.flush();
}
private:
std::ostream& m_stream;
std::stringstream m_ss;
};
Use it like:
log() << "All this text" << " will be on one line in the logfile, with date and time prepended ";
log() << "And this lot falls on line 2, with date and time prepended";
I hope that helps Galik and others who may be wanting the same thing.
A small improvement to the solution offered in the question, that creates fewer temporary objects:
class log
{
public:
log() :
m_stream(cpp::app::g_app->stream()){
}
template <typename T>
std::ostream& operator<< (const T& t)
{
return m_stream << cpp::timing::currentDateTime() << "\t" << t;
}
virtual ~log(){
m_stream << "\r\n";
m_stream.flush();
}
private:
std::ostream& m_stream;
};
The temporary instance of log() will be destroyed at the end of the full-expression even if it isn't returned from operator<<. Might as well get rid of the middle-man and the extra stringstream buffer (which btw, doesn't respect the existing formatting options on the main stream -- this could be good or bad)
I have some code that you may find useful.
Its not heavily tested. I am hoping to expand on this to supply a producer/consumer queue which is why I am not using it at the moment. I am still using a macro like you :)
#include <sstream>
#include <memory>
#include <fstream>
#include <iostream>
#include <ctime>
namespace log {
typedef std::stringstream sss; // <3 brevity
class writer
{
private:
std::ostream& sink;
std::string endl = "\n";
std::string get_stamp()
{
time_t rawtime = std::time(0);
tm* timeinfo = std::localtime(&rawtime);
char buffer[32];
std::strftime(buffer, 32, "%Y-%m-%d %H:%M:%S", timeinfo);
return std::string(buffer);
}
public:
writer(std::ostream& sink): sink(sink) {}
void add_line(sss* ss)
{
sink << get_stamp() << " " << ss->rdbuf() << endl;
}
};
// this is used to build the log string in an sts::ostringstream
// which gets std::moved to each new temporary buffer when <<
// is invoked
struct buffer
{
writer& lw;
sss* ss;
buffer(writer& lw): lw(lw), ss(new sss) {}
buffer(const buffer& buf) = delete;
buffer(buffer&& buf): lw(buf.lw), ss(buf.ss) { buf.ss = nullptr; }
~buffer() { if(ss) lw.add_line(ss); delete ss; }
};
// each << creates a new temporary buffer that std::moves
// the std::ostringstream on to the next
template<typename Type>
buffer operator<<(buffer&& buf, const Type& t)
{
(*buf.ss) << t;
return std::move(buf);
}
// A write to a writer creates a temporary buffer and passes
// the << on to that
template<typename Type>
buffer operator<<(writer& lw, const Type& t)
{
return std::move(buffer(lw) << t);
}
} // log
int main()
{
std::ofstream ofs("output.log");
log::writer fout(ofs); // write to file
log::writer lout(std::cout); // write to std output
lout << "A " << 0.7 << " B";
fout << "wibble: " << 2;
}
The way this works is that writing to a log::writer via << causes a temporary log::buffer to be created. Subsequent writes << to the log::buffer create new temporary log::buffer objects which std::move an internal std::ostringstream between them. Because only the final log::buffer object has a non-null std::ostringstream* (because it was std::moved down when it collapsed) it writes the entire line to the log::writer.
My rather simple take on the situation:
class logger{
private:
unsigned int support_count;
std::ostream& output_stream;
public:
logger(std::ostream& str)
:support_count(0),
output_stream(str)
{}
class support_buffer{
private:
logger& l;
support_buffer(logger& l)
:l(l)
{
l.support_count++;
}
public:
support_buffer(const support_buffer& buf)
:l(buf.l)
{
l.support_count++;
}
~support_buffer(){
l.support_count--;
if (l.support_count==0){
l.output_stream << std::endl;
}
}
template <typename T>
support_buffer& operator<<(const T& t){
l.output_stream << t;
return *this;
}
friend class logger;
};
template <typename T>
support_buffer operator<<(const T& t){
output_stream << "<date/time> " << t;
return support_buffer(*this);
}
friend class support_buffer;
};
int main()
{
logger l(std::cout);
l << "Line 1: " << 0 << "Still on line 1";
l << "Line 2";
return 0;
}
Just create a wrapper class that passes all printed elements to our logger and on destruction of the last one send a new line. If you are sure that your output buffer is only being used by your logger class you could even resign of counting support objects. Just print new line character before a line instead of after it.

Best way to add a "prompt" message to std::cout

I'm searching the best way to add a custom, initial message to all the messages that std::cout (or std::cerr) prints to console/file output.
For example, if I setup that this custom prompt message will be the string "[Log]", then a classic
std::cerr << "This is a log message" << std::endl;
will be printed in this way:
> [Log] This is a log message
Clearly I can obtain this behavior using
std::string PROMPT_MSG = "[Log]";
std::cerr << PROMPT_MSG << "This is a log message" << std::endl;
but I'd like a less invasive way.
Thanks in advance
You could write your own class:
#include <iostream>
#include <string>
class MyLogger
{
std::ostream & out;
std::string const msg;
public:
MyLogger(std::ostream & o, std::string s)
: out(o)
, msg(std::move(s))
{ }
template <typename T>
std::ostream & operator<<(T const & x)
{
return out << msg << x;
}
};
MyLogger MyErr(std::cerr, "[LOG] ");
Usage:
MyErr << "Hello" << std::endl;
As Joachim Pileborg suggested you can use a logging framework. YOu can use an existing one or start with your own that will contain just one class:
class MyLogger{}
template <typename T>
MyLogger& operator << (MyLogger& logger, const T& logStuff)
{
std::cerr << PROMPT_MSG << logStuff << std::endl;
return logger;
}
then define a global variable of class MyLogger:
MyLogger mylogger;
then when you want to write a log record, write:
mylogger << "This is a log message";
overloaded operator << of class MyLogger will do what you want;
I had the same problem in a recent project. I solved it with this little class:
class DebugOut
{
public:
static const int COLUMN_WIDTH = 15;
DebugOut(const std::wstring &type)
{
std::wcout << type;
for(int i=type.length();i<COLUMN_WIDTH;i++)
std::wcout << " ";
std::wcout << ": ";
}
~DebugOut()
{
std::wcout << std::endl;
}
template <typename T>
friend DebugOut& operator<<(DebugOut& out,T i)
{
std::wcout << i;
return out;
}
};
Sample usage: DebugOut(L"Log") << "Something";
I guess you could just define a function log and a function error, and then just call them when you want to print a log or error method. That way you don't have to add the PROMPT_MSG every time.

customize cout

How can I derive a class from cout so that, for example, writing to it
new_cout << "message";
would be equivalent to
cout << __FUNCTION__ << "message" << "end of message" << endl;
class Log
{
public:
Log(const std::string &funcName)
{
std::cout << funcName << ": ";
}
template <class T>
Log &operator<<(const T &v)
{
std::cout << v;
return *this;
}
~Log()
{
std::cout << " [end of message]" << std::endl;
}
};
#define MAGIC_LOG Log(__FUNCTION__)
Hence:
MAGIC_LOG << "here's a message";
MAGIC_LOG << "here's one with a number: " << 5;
#define debug_print(message) (std::cout << __FUNCTION__ << (message) << std::endl)
This has the advantage that you can disable all debug messages at once when you're done
#define debug_print(message) ()
Further from Mykola's response, I have the following implementation in my code.
The usage is
LOG_DEBUG("print 3 " << 3);
prints
DEBUG (f.cpp, 101): print 3 3
You can modify it to use FUNCTION along/in place of LINE and FILE
/// Implements a simple logging facility.
class Logger
{
std::ostringstream os_;
static Logger* instance_;
Logger();
public:
static Logger* getLogger();
bool isDebugEnabled() const;
void log(LogLevelEnum l, std::ostringstream& os, const char* filename, int lineno) const;
std::ostringstream& getStream()
{ return os_; }
};
void Logger::log(LogLevelEnum l, std::ostringstream& os, const char* filename, int lineno) const
{
std::cout << logLevelEnumToString(l) << "\t(" << fileName << ": " << lineno << ")\t- " << os.str();
os.str("");
}
#define LOG_common(level, cptext) do {\
utility::Logger::getLogger()->getStream() << cptext; \
utility::Logger::getLogger()->log(utility::level, utility::Logger::getLogger()->getStream(), __FILE__, __LINE__); \
} while(0);
enum LogLevelEnum {
DEBUG_LOG_LEVEL,
INFO_LOG_LEVEL,
WARN_LOG_LEVEL,
ERROR_LOG_LEVEL,
NOTICE_LOG_LEVEL,
FATAL_LOG_LEVEL
};
#define LOG_DEBUG(cptext) LOG_common(DEBUG_LOG_LEVEL, cptext)
#define LOG_INFO(cptext) LOG_common(INFO_LOG_LEVEL , cptext)
#define LOG_WARN(cptext) LOG_common(WARN_LOG_LEVEL , cptext)
#define LOG_ERROR(cptext) LOG_common(ERROR_LOG_LEVEL, cptext)
#define LOG_NOTICE(cptext) LOG_common(NOTICE_LOG_LEVEL, cptext)
#define LOG_FATAL(cptext) LOG_common(FATAL_LOG_LEVEL, cptext)
const char* logLevelEnumToString(LogLevelEnum m)
{
switch(m)
{
case DEBUG_LOG_LEVEL:
return "DEBUG";
case INFO_LOG_LEVEL:
return "INFO";
case WARN_LOG_LEVEL:
return "WARN";
case NOTICE_LOG_LEVEL:
return "NOTICE";
case ERROR_LOG_LEVEL:
return "ERROR";
case FATAL_LOG_LEVEL:
return "FATAL";
default:
CP_MSG_ASSERT(false, CP_TEXT("invalid value of LogLevelEnum"));
return 0;
}
}
For logging purposes I use something like
#define LOG(x) \
cout << __FUNCTION__ << x << endl
// ...
LOG("My message with number " << number << " and some more");
The problem with your approach is (as Mykola Golybyew explained) that FUNCTION is processed at compile time and would therefore always print the same name with a non-preprocessor solution.
If it's only for adding endl to your messages, you could try something like:
class MyLine {
public:
bool written;
std::ostream& stream;
MyLine(const MyLine& _line) : stream(_line.stream), written(false) { }
MyLine(std::ostream& _stream) : stream(_stream), written(false) { }
~MyLine() { if (!written) stream << "End of Message" << std::endl; }
};
template <class T> MyLine operator<<(MyLine& line, const T& _val) {
line.stream << _val;
line.written = true;
return line;
}
class MyStream {
public:
std::ostream& parentStream;
MyStream(std::ostream& _parentStream) : parentStream(_parentStream) { }
MyLine getLine() { return MyLine(parentStream); }
};
template <class T> MyLine operator<<(MyStream& stream, const T& _val) {
return (stream.getLine() << _val);
}
int main()
{
MyStream stream(std::cout);
stream << "Hello " << 13 << " some more data";
stream << "This is in the next line " << " 1 ";
return 0;
}
Note, that it's important not to return references from the operator functions. Since the MyLine should only exist as a temporary (for its destructor triggers the writing of the endl), the first object (returned by the getLine() function in MyStream) would be destructed before the second operator<< is called. Therefore the MyLine object is copied in each operator<< creating a new one. The last object gets destructed without being written to and writed the end of the message in its destructor.
Just try it out in the debugger to understand whats going on...
You have to override operator<<(), but you even don't have to subclass std::cout. You may also create a new object or use existing objects like that.
You could also override the operator. It will allow you to call another function or prefix/suffix anything that's going to leave the output buffer with whatever you wish: In your case, you'd have it output a specific string.