I want to extend the usage of std::cout to use my own console/cout wrapper class.
Ideally I would have 2 ostreams, one for regular printing and one that appends a new line.
std::ostream Write;
Write << "Hello, I am " << 99 << " years old.";
prints Hello, I am 99 years old.
std::ostream WriteLine;
WriteLine << "Hello, I am " << 99 << " years old.";
prints Hello, I am 99 years old.\n (an actual new line, not just it escaped)
I would then like to extend this to have error streams (Error and ErrorLine, for example) which prefix "ERROR: " before the message and prints in a different color.
I know I have to create my own streams to add in this functionality, and I followed C++ cout with prefix for prefixing std::cout which was almost what I wanted but not quite. I couldn't figure out how to add a new line to the end of the stream, and the prefix was unreliable, especially when I would do more than a single print statement.
I should also mention I don't want to use overloaded operators to achieve this effect, because I want to be able to daisy-chain things on.
What didn't work
If I did WriteLine >> "First"; then WriteLine << "Second"; I would get weird results like SecondFirst\n or Second\nFirst. My ideal output would be First\nSecond\n. I think it is due to not closing/flushing/resetting the stream properly, but nothing I tried got it to work reliably.
I could get it to work for a single statement, but as soon as I added another print statement, the things I tried to print would switch order, the post/pre fix wouldn't get added in the correct spot, or I would end up with garbage.
I don't care about wchars, because we will always only need a single byte for a single char. Also we will only be working on Windows 10.
This is what I have so far:
Console.h
#include <windows.h>
#include <iostream>
#include <sstream>
#include <string>
class Console {
using Writer = std::ostream;
Console() {}
static const char newline = '\n';
class error_stream: public std::streambuf {
public:
error_stream(std::streambuf* s) : sbuf(s) {}
~error_stream() { overflow('\0'); }
private:
typedef std::basic_string<char_type> string;
int_type overflow(int_type c) {
if(traits_type::eq_int_type(traits_type::eof(), c))
return traits_type::not_eof(c);
switch(c) {
case '\n':
case '\r':
{
SetColor(ConsoleColor::Red);
prefix = "ERROR: ";
buffer += c;
if(buffer.size() > 1)
sbuf->sputn(prefix.c_str(), prefix.size());
int_type rc = sbuf->sputn(buffer.c_str(), buffer.size());
buffer.clear();
SetColor(ConsoleColor::White);
return rc;
}
default:
buffer += c;
return c;
}
}
std::string prefix;
std::streambuf* sbuf;
string buffer;
};
class write_line_stream: public std::streambuf {
public:
write_line_stream(std::streambuf* s) : sbuf(s) {}
~write_line_stream() { overflow('\0'); }
private:
typedef std::basic_string<char_type> string;
int_type overflow(int_type c) {
if(traits_type::eq_int_type(traits_type::eof(), c))
return traits_type::not_eof(c);
switch(c) {
case '\n':
case '\r':
{
buffer += c;
int_type rc = sbuf->sputn(buffer.c_str(), buffer.size());
sbuf->sputn(&newline, 1);
buffer.clear();
return rc;
}
default:
buffer += c;
return c;
}
}
std::streambuf* sbuf;
string buffer;
};
static output_stream outputStream;
static error_stream errorStream;
static write_line_stream writeLineStream;
public:
static void Setup();
static Writer Write;
static Writer WriteLine;
static Writer Err;
};
Console.cpp
#include "Console.h"
Console::Writer Console::Write(nullptr);
Console::Writer Console::WriteLine(nullptr);
Console::Writer Console::Err(nullptr);
Console::error_stream Console::errorStream(std::cout.rdbuf());
Console::write_line_stream Console::writeLineStream(std::cout.rdbuf());
void Console::Setup() {
Write.rdbuf(std::cout.rdbuf());
Err.rdbuf(&errorStream);
WriteLine.rdbuf(&writeLineStream);
}
Main.cpp
int main() {
Console::Setup();
Console::Write << "First" << "Second";
Console::WriteLine << "Third";
Console::WriteLine << "Fourth";
Console::Write << "Fifth";
Console::Error << "Sixth";
Console::ErrorLine << "Seventh";
Console::WriteLine << "Eighth";
}
Which should give an output of
FirstSecondThird
Fourth
FifthERROR: SixthERROR: Seventh
Eighth
Press any key to continue...
Any help and/or suggestions are appreciated.
There are multiple concerns here which do require different approaches. Some of the description also seems that the actual desire isn't quite clear. The most problematic requirement is that a newline needs to be inserted apparently at the end of a statement. That's certainly doable but effectively does require a temporary being around.
Before going there I want to point out that most other languages offering a print-line(....) construct delineate what is going onto a line using a function call. There is no doubt where the newline goes. If C++ I/O would be created now I'd be quite certain that it would be based on a variadic (not vararg) function template. This way print something at the end of the expression is trivial. Using a suitable manipulator at the end of the line (although probably not std::endl but maybe a custom nl) would be an easy approach.
The basics of adding a newline at the end of expression would be using a destructor of a suitable temporary object to add it. The straight forward way would be something like this:
#include <iostream>
class newline_writer
: public std::ostream {
bool need_newline = true;
public:
newline_writer(std::streambuf* sbuf)
: std::ios(sbuf), std::ostream(sbuf) {
}
newline_writer(newline_writer&& other)
: newline_writer(other.rdbuf()) {
other.need_newline = false;
}
~newline_writer() { this->need_newline && *this << '\n'; }
};
newline_writer writeline() {
return newline_writer(std::cout.rdbuf());
}
int main() {
writeline() << "hello, " << "world";
}
This works reasonable nice. The notation in the question doesn't use a function call, though. So, instead of writing
writeline() << "hello";
it seems necessary to write
writeline << "hello";
instead and still add a newline. This complicates matters a bit: essentially, writeline now needs to be an object which somehow causes another object to jump into existence upon use so the latter can do its work in the destructor. Using a conversion won't work. However, overloading an output operator to return a suitable object does work, e.g.:
class writeliner {
std::streambuf* sbuf;
public:
writeliner(std::streambuf* sbuf): sbuf(sbuf) {}
template <typename T>
newline_writer operator<< (T&& value) {
newline_writer rc(sbuf);
rc << std::forward<T>(value);
return rc;
}
newline_writer operator<< (std::ostream& (*manip)(std::ostream&)) {
newline_writer rc(sbuf);
rc << manip;
return rc;
}
} writeline(std::cout.rdbuf());
int main() {
writeline << "hello" << "world";
writeline << std::endl;
}
The primary purpose of the overloaded shift operators is to create a suitable temporary object. They don't try to mess with the content of the character stream. Personally, I'd rather have the extra parenthesis than using this somewhat messy approach but it does work. What is kind of important is that the operator is also overloaded for manipulators, e.g., to allow the second statement with std::endl. Without the overload the type of endl can't be deduce.
The next bit is writing the prefix and mixing multiple streams. The important bit here is to realize that you'd want to one of two things:
Immediately write the characters to a common buffer. The buffer is most like just another stream buffer, e.g., the destination std::streambuf.
If the character should be buffered locally in separate stream buffers, the corresponding streams need be flushed in a timely manner, e.g., after each insertion (by setting the std::ios_base::unitbuf bit) or, latest, at the end of the expression, e.g., using an auxiliary class similar to the newline_writer.
Passing through the characters immediately is fairly straight forward. The only slight complication is to know when to write a prefix: upon the first non-newline, non-carriage-return return after a newline or a carriage return (other definitions are possibly and should be easily adaptable). The important aspect is that stream buffer doesn't really buffer but actually passes through the character to the underlying [shared] stream buffer:
class prefixbuf
: public std::streambuf {
std::string prefix;
bool need_prefix = true;
std::streambuf* sbuf;
int overflow(int c) {
if (c == std::char_traits<char>::eof()) {
return std::char_traits<char>::not_eof(c);
}
switch (c) {
case '\n':
case '\r':
need_prefix = true;
break;
default:
if (need_prefix) {
this->sbuf->sputn(this->prefix.c_str(), this->prefix.size());
need_prefix = false;
}
}
return this->sbuf->sputc(c);
}
int sync() {
return this->sbuf->pubsync();
}
public:
prefixbuf(std::string prefix, std::streambuf* sbuf)
: prefix(std::move(prefix)), sbuf(sbuf) {
}
};
The remaining business is to set up the relevant objects in the Console namespace. However, doing so is rather straight forward:
namespace Console {
prefixbuf errorPrefix("ERROR", std::cout.rdbuf());
std::ostream Write(std::cout.rdbuf());
writeliner WriteLine(std::cout.rdbuf());
std::ostream Error(&errorPrefix);
writeliner ErrorLine(&errorPrefix);
}
I except that the approach adding the newline creates a custom type I think that matches the original goes. I don't think the temporary object can be avoided to automatically create a newline at the end of a statement.
All that said, I think you should use C++ idioms and not try to replicate some other language in C++. The way to choose whether a line end in newline or not in C++ is to write, well, a newline where one should appear potentially by way of a suitable manipulator.
Related
In C++, how do I detect if my std::ostream os is at the start of a line, in other words (I think) the most recent thing written to os is either os<<'\n' or os<<std::endl(), or else nothing has yet been written to os?
At first glance, this sounds unnecessary, because I can just keep track of the state myself. But a common scenario is the following, where keeping track would involve altering every os<<thing statement which could possibly be called from the try block, in a very unnatural way.
try {
do_something_which_writes_to(std::cout);
}
catch(const My_error&error) {
print_a_newline_if_necessary(std::cout);
std::cout<<error<<"\n";
}
(In reality, of course, we want to write error to std::cerr but that usually gets mixed in with std::cout unless one of them is redirected, so we still want to terminate the std::cout line before printing to std::cerr. I have deliberately simplified the example to avoid this distraction.)
You might imagine that os.tellp() would be the answer, but tellp() seems to work only on std::ofstream. For me at least, std::cout.tellp() always returns -1, indicating that it is not supported.
At least as I'm reading things, what you really want isn't the ability to get the position in the current line. Rather, what you really want is to be able to print something that is guaranteed to be at the start of a line--the current line if the immediately previous character was a newline (and, I'd guess also if it was a carriage return), but otherwise print a newline, then whatever follows.
Here's some code to do that:
#include <iostream>
class linebuf : public std::streambuf
{
std::streambuf* sbuf;
bool need_newline;
int sync() {
return sbuf->pubsync();
}
int overflow(int c) {
switch (c) {
case '\r':
case '\n': need_newline = false;
break;
case '\v':
if (need_newline) {
need_newline = false;
return sbuf->sputc('\n');
}
return c;
default:
need_newline = true;
break;
}
return sbuf->sputc(c);
}
public:
linebuf(std::streambuf* sbuf)
: sbuf(sbuf)
, need_newline(true)
{}
std::streambuf *buf() const { return sbuf; }
~linebuf() { sync(); }
};
class linestream : public std::ostream {
linebuf buf;
std::ostream &os;
public:
linestream(std::ostream& out)
: buf(out.rdbuf())
, std::ios(&buf)
, std::ostream(&buf)
, os(out)
{
out.rdbuf(&buf);
}
~linestream() { os.rdbuf(buf.buf()); }
};
void do_stuff() {
std::cout << "\vMore output\v";
}
int main() {
{
linestream temp(std::cout);
std::cout << "\noutput\n";
std::cout << "\voutput";
do_stuff();
std::cout << "\voutput\n";
std::cout << "\voutput\v";
}
std::cout << "\voutput\v";
}
Since it's almost never used otherwise, I've hijacked the vertical tab ('\v') to signify the special behavior.
To use it, you simply create a temporary object of type linestream (sorry, I'm too tired to think of a good name right now), passing it an ostream object that will get the new behavior when a \v gets written to it. When that temporary object goes out of scope, the stream will be restored to its original behavior (I doubt anybody uses \v often enough to care, but who knows maybe somebody care--it's mostly just a side effect of cleaning up after itself anyway).
In any case, the special behavior remains in place when do_stuff is called, so it's not just local to the function where the local linestream object is created, or anything like that--once it's created, the special behavior remains in effect until it's destroyed.
One other point though: when/if you mix output from cout and cerr, this won't help much. In particular, neither will be at all aware of the other's state. You'd probably much need some hooks into the output terminal (or something on that order) to be able to deal with that, since output redirection is normally handled by the OS, so inside the program there's no way to even guess whether data written to cout and cerr are going to the same place or not.
I'd like an interface for writing to an automatically resizing array. One way to do this is with a generic std::ostream *.
Then consider if ostringstream is the target:
void WritePNG(ostream *out, const uint8_t *pixels);
void *WritePNGToMemory(uint8_t *pixels)
{
ostringstream out;
WritePng(&out, pixels);
uint8_t *copy = new uint8_t[out.tellp()];
memcpy(copy, out.str().c_str(), out.tellp()];
return copy;
}
But I want to avoid the memcpy(). Is there a way to take ownership of the array in the underlying stringbuf class and return that?
I get the feeling this can't be done using standard library, since the stream buffer might not even be a contiguous array.
If you're willing to use the old, deprecated <strstream> interface, this is fairly easy - just create a std::strstreambuf pointing at your storage, and it will work by magic. std::ostrstream even has a constructor to do this for you:
#include <iostream>
#include <strstream>
int main()
{
char copy[32] = "";
std::ostrstream(copy, sizeof copy) << "Hello, world!"
<< std::ends << std::flush;
std::cout << copy << '\n';
}
With the more modern <sstream> interface, you need to access the string stream's buffer, and call pubsetbuf() to make it to point at your storage:
#include <iostream>
#include <sstream>
int main()
{
char copy[32] = "";
{
std::ostringstream out{};
out.rdbuf()->pubsetbuf(copy, sizeof copy);
out << "Hello, world!" << std::ends << std::flush;
}
std::cout << copy << '\n';
}
Obviously, in both cases, you'll need a way to know in advance how much memory to allocate for copy, because you can't wait until tellp() is ready for you...
Here's the solution I ended up using. The idea is the same as the one proposed by HostileFork - only needing to implement overflow(). But as already hinted, it has much better throughput by buffering. It also optionally supports random access (seekp(), tellp()).
class MemoryOutputStreamBuffer : public streambuf
{
public:
MemoryOutputStreamBuffer(vector<uint8_t> &b) : buffer(b)
{
}
int_type overflow(int_type c)
{
size_t size = this->size(); // can be > oldCapacity due to seeking past end
size_t oldCapacity = buffer.size();
size_t newCapacity = max(oldCapacity + 100, size * 2);
buffer.resize(newCapacity);
char *b = (char *)&buffer[0];
setp(b, &b[newCapacity]);
pbump(size);
if (c != EOF)
{
buffer[size] = c;
pbump(1);
}
return c;
}
#ifdef ALLOW_MEM_OUT_STREAM_RANDOM_ACCESS
streampos MemoryOutputStreamBuffer::seekpos(streampos pos,
ios_base::openmode which)
{
setp(pbase(), epptr());
pbump(pos);
// GCC's streambuf doesn't allow put pointer to go out of bounds or else xsputn() will have integer overflow
// Microsoft's does allow out of bounds, so manually calling overflow() isn't needed
if (pptr() > epptr())
overflow(EOF);
return pos;
}
// redundant, but necessary for tellp() to work
// https://stackoverflow.com/questions/29132458/why-does-the-standard-have-both-seekpos-and-seekoff
streampos MemoryOutputStreamBuffer::seekoff(streamoff offset,
ios_base::seekdir way,
ios_base::openmode which)
{
streampos pos;
switch (way)
{
case ios_base::beg:
pos = offset;
break;
case ios_base::cur:
pos = (pptr() - pbase()) + offset;
break;
case ios_base::end:
pos = (epptr() - pbase()) + offset;
break;
}
return seekpos(pos, which);
}
#endif
size_t size()
{
return pptr() - pbase();
}
private:
std::vector<uint8_t> &buffer;
};
They say a good programmer is a lazy one, so here's an alternate implementation I came up with that needs even less custom code. However, there's a risk for memory leaks because it hijacks the buffer inside MyStringBuffer, but doesn't free MyStringBuffer. In practice, it doesn't leak for GCC's streambuf, which I confirmed using AddressSanitizer.
class MyStringBuffer : public stringbuf
{
public:
uint8_t &operator[](size_t index)
{
uint8_t *b = (uint8_t *)pbase();
return b[index];
}
size_t size()
{
return pptr() - pbase();
}
};
// caller is responsible for freeing out
void Test(uint8_t *&_out, size_t &size)
{
uint8_t dummy[sizeof(MyStringBuffer)];
new (dummy) MyStringBuffer; // construct MyStringBuffer using existing memory
MyStringBuffer &buf = *(MyStringBuffer *)dummy;
ostream out(&buf);
out << "hello world";
_out = &buf[0];
size = buf.size();
}
IIRC the whole reason stringstream exists (vs strstream) was to sort out the fuzzy questions of memory ownership that would come up by giving direct buffer access. e.g. I think that change was to specifically prevent what you are asking to do.
One way or another I think you'd have to do it yourself, by overriding the stream buffer. To answer a similar question I suggested something for input streams that wound up getting quite a few upvotes. But honestly I didn't know what I was talking about then, nor now when I suggest the following:
Hacking up this link from the web for doing an "uppercasing stream buffer" to one that just echoes and gives you a reference to its buffer might give:
#include <iostream>
#include <streambuf>
class outbuf : public std::streambuf {
std::string data;
protected:
virtual int_type overflow (int_type c) {
if (c != EOF)
data.push_back(c);
return c;
}
public:
std::string& get_contents() { return data; }
};
int main() {
outbuf ob;
std::ostream out(&ob);
out << "some stuff";
std::string& data = ob.get_contents();
std::cout << data;
return 0;
}
I'm sure it's broken in all kinds of ways. But the uppercase-buffer-authors seemed to think that overriding the overflow() method alone would let them uppercase all output to the stream, so I guess one could argue that it's enough to see all output if writing to one's own buffer.
But even so, going one character at a time seems suboptimal...and who knows what overhead you get from inheriting from streambuf in the first place. Consult your nearest C++ iostream expert for what the actual right way is. But hopefully it's proof that something of the sort is possible.
I have implemented a custom logger where I dump information to the corresponding file:
like this:
Logger::log["log_file"] << "Hi" << "Hi again" << "\n";
The implementation of the operator << is as below. Kindly note the place where the buffer is dumped into the stream when it reaches a limit:
//This is the function signature of std::endl and some other manipulators
typedef CoutType& (*StandardEndLine)(CoutType&);
/// This method defines an operator<< to take in std::endl
BasicLogger& operator<<(StandardEndLine manip);
/// write the log items to buffer
template <typename T>
BasicLogger & operator<< (const T& val)
{
std::stringstream *out = BasicLogger::getOut();
*out << val;
if(out->tellp() > 512000/*500KB*/){
flushLog();
}
return *this;
}
My problem is in the lines that have multiple <<s :
Logger::log["log_file"] << "Hi" << "Hi again" << "\n";
after executing << "Hi", the buffer can get full and flushing to the stream is performed.
This is not desirable for me . I am looking for a solution to ignore that limit(500KB) if a line has not ended yet.
Example scenario:
This problem is highlighted when the application writes buffers filled by different threads to the same file: the last line of the first buffer is half written, when the second buffer from another thread writes another 500kb to the file before I can complete the last line of the first buffer.
I appreciate your thoughts and solutions.
thanks
The traditional solution to grouping multiple << into a single flush is to use a temporary sentry object which is destroyed at the end of the statement.
The destructor would flush (if required), and you can even have it append a newline automatically if that's what you want. As per Andrew Medico's comment, the sentry ctor/dtor should lock/unlock as well, if you need synchronization.
An alternative is to gather everything into a local ostringstream in the sentry, and then you only have to lock/write/flush/unlock a single string from the dtor.
Details:
your Logger::log["log_file"] operator should return a temporary object with the behaviour you chose from the options above
your various << are operator calls taking as the first argument, and returning, a reference to your sentry type
at the ;, the temporary sentry goes out of scope and does any flushing work in its destructor.
Note that if you're just delegating to an existing ostream, you can easily have a single templated Logger::sentry& operator<< (Logger::sentry&, T).
Edit: I thought I'd done this before: the question isn't a duplicate, but the answer is. https://stackoverflow.com/a/19520409/212858
I am looking for a solution to ignore that limit(500KB) if a line has not ended yet.
Why not just check that the last character is a '\n' before flushing the log?
If I knew what was in T, I would give you an example. If its a c++11 string you can just do:
char ch = val.getString().back();
if(out->tellp() > 512000/*500KB*/ && ch == '\n'){
flushLog();
}
Simply flag a carrage return:
bool ended = out.str().find('\n') != string::npos;
if(out->tellp() > 512000/*500KB*/ && ended) {
You can change the implementation of the flushLog method. I assume your implementation writes the contents of the internal stringstream into a file and clears it. You can output the contents of the stringstream only up to the last newline:
void Whatever::flushLog()
{
std::stringstream& out = *BasicLogger::getOut();
std::string stuff = out.str();
size_t pos_of_newline = stuff.rfind('\n');
if (pos_of_newline != std::string::npos)
{
std::string write_it_to_file = stuff.substr(0, pos_of_newline + 1);
... write it to file
std::string leftover = stuff.substr(pos_of_newline + 1);
out.str(leftover);
}
}
The code is only an idea; I didn't check it - maybe there are some bugs. In additon: the str() call duplicates the contents of the stringstream; you might want to use its rdbuf instead (I have no experience with rdbuf, so cannot recommend anything).
Following Useless's suggestion (A suggestion shot by a user called Useless!!!),
I solved my issue using Sentry(temporary) objects:
Logger::log["log_file"] will return the correct instance of BasicLogger
operator<< in BasicLogger will return a copy of a Sentry object.
The subsequent <<s will be taken care of by operator<< in the Sentry object
Sentry will eventually goes out of scope upon hitting ; where its destructor will do the main job:
class BasicLogger {
/// operator overload. write the log items to buffer
template<typename T>
Sentry operator<<(const T& val) {
Sentry t(*this,*getOut());
t << val;//do the first << here
return t;
}
//...
class Sentry {
std::stringstream &out;
BasicLogger &basicLogger;
public:
Sentry(BasicLogger & basicLogger_, std::stringstream &out_) :
out(out_), basicLogger(basicLogger_) {
}
Sentry(const Sentry& t) :
basicLogger(t.basicLogger), out(t.out) {
}
template<typename T>
/// operator overload
Sentry & operator<<(const T& val) {
out << val;
return *this;
}
~Sentry() {
// by some googling this estimated hardcode value promises less cycles to write to a file
if (out.tellp() > 512000/*500KB*/) {
basicLogger.flushLog();
}
}
};
//...
};
class Logger {
//...
public:
static Logger log;
virtual BasicLogger & operator[](const std::string &key);
virtual ~Logger();
};
I don't know why this is erroring, but I'm just trying to add something "akin" to endl so that I can throw what's in an ostringstream to our debugger. I have the following:
class debug_stream_info
{
public:
debug_stream_info(int errorLine, char *errorFile, int level)
:m_errorLine(errorLine), m_errorFile(errorFile), m_logLevel(level)
{
}
friend std::basic_ostringstream<char>& operator<<(std::basic_ostringstream<char>& os, debug_stream_info& debug_info);
private:
int m_errorLine;
std::string m_errorFile;
int m_logLevel;
};
std::basic_ostringstream<char>& operator<<(std::basic_ostringstream<char>& os, debug_stream_info& debug_info)
{
// Write the stream's contents to cpu_debug
// Deleted custom logging function. No errors here though
// Clear the stream for re-use.
os.str("");
os.seekp(0);
return os;
}
int main(int argc, char** argv)
{
std::ostringstream myout;
myout << "hey there" << " and some more " << "Numbers!!: " << 435 << 54.2 << " that's good for numbers" << debug_stream_info(__LINE__, __FILE__, LOG_LEVEL);
return 0;
}
The error I'm getting is: error C2679: binary '<<' : no operator found which takes a right-hand operand of type 'debug_stream_info' (or there is no acceptable conversion) for the line in main. This is on VS2008.
I'm including sstream, iostream, etc, and have the namespaces set up right. I'm getting no other errors. I even tried replacing all occurrances of basic_ostream with just ostringstream and there was no difference (I'll be having a w_char version later, but I wanted the simple case to work first). I made the object on the line above and then passed a fully-constructed object on the line, and the error was exactly the same. I've changed the signature of the second argument to and from const with no change as well.
Any ideas on what I'm doing wrong here?
Edit: since EVERY response seems to want to put it there, I can NOT use std::ostream because I want this to work ONLY for std::ostringstream (and std::basic_ostringstream) and not for any type of output stream. Besides, the function wouldn't compile with ostream anyways, since I'm using the os.str() method, which isn't in ostream, only the sub-classes.
The real problem with your code is that you've overloaded std::ostringstream rather than std::ostream. So your code would work if you write this:
debug_stream_info info(/** blah blah**/);
std::ostringstream oss;
oss << info ; //OK
However this will not work:
oss << 1 << info; //ERROR
This is compilation error because the expression oss<<1 returns an object of type std::ostream& which doesn't have overload which takes debug_stream_info as second argument. That means if you use cast as:
static_cast<std::ostringstream&>(oss << 1) << info; //OK
then that should work again.
So the solution is to overload std::ostream, instead of std::basic_ostringstream.
Also, the second parameter should be const & . This is also a problem with your code.
So write this:
std::ostream& operator<<(std::ostream&, debug_stream_info const &);
//^^^^^^^ note this
The second parameter should be const & so that you could write temporary objects to the stream.
debug_stream_info(__LINE__, __FILE__, LOG_LEVEL); is creating unnamed object which is not returning anything hence error
#include <iostream>
#include <cstdio>
#include <sstream>
using namespace std;
class debug_stream_info
{
public:
debug_stream_info(int errorLine, char *errorFile, int level)
:m_errorLine(errorLine), m_errorFile(errorFile), m_logLevel(level)
{
}
friend std::basic_ostringstream<char>& operator<<(std::basic_ostringstream<char>& os, debug_stream_info& debug_info);
std::ostringstream& fun(std::ostringstream& os)
{
os<<"Ashish"<<endl;
return os;
}
private:
int m_errorLine;
std::string m_errorFile;
int m_logLevel;
};
std::basic_ostringstream<char>& operator<<(std::basic_ostringstream<char>& os, debug_stream_info& debug_info)
{
// Write the stream's contents to cpu_debug
// Deleted custom logging function. No errors here though
// Clear the stream for re-use.
// os.str("");
// os.seekp(0);
return os;
}
int main(int argc, char** argv)
{
std::ostringstream myout, test;
myout << "hey there" << " and some more " << "Numbers!!: " << 435 << 54.2 << " that's good for numbers"
<< debug_stream_info(1, "/home/ashish/test", 1).fun(test);
return 0;
}
Nawaz has explained very clearly why you're getting the error. The
usual solution in this case is to define your own stream type, unrelated
to std::istream. Something along the lines of:
class DebugStream
{
std::ostringstring* collector;
public:
template <typename T>
DebugStream& operator<<( T const& value )
{
if ( collector != NULL ) {
*collector << value;
}
return *this;
}
};
There are infinite variations on this; in your case, you could add a
non-template member function for your type; more likely, you'd add a
constructor which took the same arguments:
DebugStream( int lineNumber, std::string const& filename, int logLevel )
: collector( isActive( logLevel ) ? new std::ostringstream : NULL )
{
// Initial insertion of lineNumber, filename, timestamp...
}
You can also add a destructor which atomically flushes the collected
data to a file (or sends an email, or writes it to the system log, or
whatever). (Be very careful about this. You don't want an exception to
escape from the destructor, even if the logging fails.)
Finally, you might want to use a custom streambuf, rather than
stringstream. Say one that keeps the allocated buffer from one
instance to the next. And if you do this, rather than newing the
stream each time, you might pick up an instance from a table, indexed by
the log level (and initialized from a configuration file).
I want to define a class MyStream so that:
MyStream myStream;
myStream << 1 << 2 << 3 << std::endl << 5 << 6 << std::endl << 7 << 8 << std::endl;
gives output
[blah]123
[blah]56
[blah]78
Basically, I want a "[blah]" inserted at the front, then inserted after every non terminating std::endl?
The difficulty here is NOT the logic management, but detecting and overloading the handling of std::endl. Is there an elegant way to do this?
Thanks!
EDIT: I don't need advice on logic management. I need to know how to detect/overload printing of std::endl.
What you need to do is write your own stream buffer: When the stream buffer is flushed you output you prefix characters and the content of the stream.
The following works because std::endl causes the following.
Add '\n' to the stream.
Calls flush() on the stream
This calls pubsync() on the stream buffer.
This calls the virtual method sync()
Override this virtual method to do the work you want.
#include <iostream>
#include <sstream>
class MyStream: public std::ostream
{
// Write a stream buffer that prefixes each line with Plop
class MyStreamBuf: public std::stringbuf
{
std::ostream& output;
public:
MyStreamBuf(std::ostream& str)
:output(str)
{}
~MyStreamBuf() {
if (pbase() != pptr()) {
putOutput();
}
}
// When we sync the stream with the output.
// 1) Output Plop then the buffer
// 2) Reset the buffer
// 3) flush the actual output stream we are using.
virtual int sync() {
putOutput();
return 0;
}
void putOutput() {
// Called by destructor.
// destructor can not call virtual methods.
output << "[blah]" << str();
str("");
output.flush();
}
};
// My Stream just uses a version of my special buffer
MyStreamBuf buffer;
public:
MyStream(std::ostream& str)
:std::ostream(&buffer)
,buffer(str)
{
}
};
int main()
{
MyStream myStream(std::cout);
myStream << 1 << 2 << 3 << std::endl << 5 << 6 << std::endl << 7 << 8 << std::endl;
}
> ./a.out
[blah]123
[blah]56
[blah]78
>
Your overloaded operators of the MyStream class have to set a previous-printed-token-was-endl flag.
Then, if the next object is printed, the [blah] can be inserted in front of it.
std::endl is a function taking and returning a reference to std::ostream. To detect it was shifted into your stream, you have to overload the operator<< between your type and such a function:
MyStream& operator<<( std::ostream&(*f)(std::ostream&) )
{
std::cout << f;
if( f == std::endl )
{
_lastTokenWasEndl = true;
}
return *this;
}
Agreed with Neil on principle.
You want to change the behavior of the buffer, because that is the only way to extend iostreams. endl does this:
flush(__os.put(__os.widen('\n')));
widen returns a single character, so you can't put your string in there. put calls putc which is not a virtual function and only occasionally hooks to overflow. You can intercept at flush, which calls the buffer's sync. You would need to intercept and change all newline characters as they are overflowed or manually synced and convert them to your string.
Designing an override buffer class is troublesome because basic_streambuf expects direct access to its buffer memory. This prevents you from easily passing I/O requests to a preexisting basic_streambuf. You need to go out on a limb and suppose you know the stream buffer class, and derive from it. (cin and cout are not guaranteed to use basic_filebuf, far as I can tell.) Then, just add virtual overflow and sync. (See ยง27.5.2.4.5/3 and 27.5.2.4.2/7.) Performing the substitution may require additional space so be careful to allocate that ahead of time.
- OR -
Just declare a new endl in your own namespace, or better, a manipulator which isn't called endl at all!
I use function pointers. It sounds terrifying to people who aren't used to C, but it's a lot more efficient in most cases. Here's an example:
#include <iostream>
class Foo
{
public:
Foo& operator<<(const char* str) { std::cout << str; return *this; }
// If your compiler allows it, you can omit the "fun" from *fun below. It'll make it an anonymous parameter, though...
Foo& operator<<(std::ostream& (*fun)(std::ostream&)) { std::cout << std::endl; }
} foo;
int main(int argc,char **argv)
{
foo << "This is a test!" << std::endl;
return 0;
}
If you really want to you can check for the address of endl to confirm that you aren't getting some OTHER void/void function, but I don't think it's worth it in most cases. I hope that helps.
Instead of attempting to modify the behavior of std::endl, you should probably create a filtering streambuf to do the job. James Kanze has an example showing how to insert a timestamp at the beginning of each output line. It should require only minor modification to change that to whatever prefix you want on each line.
I had the same question, and I thought that Potatoswatter's second answer had merit: "Just declare a new endl in your own namespace, or better, a manipulator which isn't called endl at all!"
So I found out how to write a custom manipulator which is not hard at all:
#include <sstream>
#include <iostream>
class log_t : public std::ostringstream
{
public:
};
std::ostream& custom_endl(std::ostream& out)
{
log_t *log = dynamic_cast<log_t*>(&out);
if (log)
{
std::cout << "custom endl succeeded.\n";
}
out << std::endl;
return out;
}
std::ostream& custom_flush(std::ostream& out)
{
log_t *log = dynamic_cast<log_t*>(&out);
if (log)
{
std::cout << "custom flush succeeded.\n";
}
out << std::flush;
return out;
}
int main(int argc, char **argv)
{
log_t log;
log << "custom endl test" << custom_endl;
log << "custom flush test" << custom_flush;
std::cout << "Contents of log:\n" << log.str() << std::endl;
}
Here's the output:
custom endl succeeded.
custom flush succeeded.
Contents of log:
custom endl test
custom flush test
Here I've created two custom manipulators, one that handles endl and one that handles flush. You can add whatever processing you want to these two functions, since you have a pointer to the log_t object.
You can't change std::endl - as it's name suggests it is a part of the C++ Standard Library and its behaviour is fixed. You need to change the behaviour of the stream itself, when it receives an end of line . Personally, I would not have thought this worth the effort, but if you want to venture into this area I strongly recommend reading the book Standard C++ IOStreams & Locales.