Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
261 views
in Technique[技术] by (71.8m points)

iostream - C++ cout with prefix

I want a ostream with a prefix at the beginning of every line redirected on cout; I try this:

#include <iostream>
#include <thread>
class parallel_cout : public std::ostream
{
public:
parallel_cout(std::ostream& o):out(o){}

template <typename T>
std::ostream& operator<< (const T& val)
{
    out << "prefix " << val;
    return *this;
}

std::ostream& out;

};

int main()
{
 parallel_cout pc(std::cout);
 pc<<"a
b"<<"c
";
}

but i have in output

prefix a
b

without c. why this?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

The way you modify the behavior of std::ostream is not by overloading any of the output operators! Instead, you derive a class from std::streambuf and override the virtual functions overflow() and sync(). In you case you'd probably create a filtering stream buffer, i.e., you'd take another std::streambuf as argument and write a somehow modified stream of characters to this stream buffer.

Here is a quick example:

#include <iostream>

class prefixbuf
    : public std::streambuf
{
    std::string     prefix;
    std::streambuf* sbuf;
    bool            need_prefix;

    int sync() {
        return this->sbuf->pubsync();
    }
    int overflow(int c) {
        if (c != std::char_traits<char>::eof()) {
            if (this->need_prefix
                && !this->prefix.empty()
                && this->prefix.size() != this->sbuf->sputn(&this->prefix[0], this->prefix.size())) {
                return std::char_traits<char>::eof();
            }
            this->need_prefix = c == '
';
        }
        return this->sbuf->sputc(c);
    }
public:
    prefixbuf(std::string const& prefix, std::streambuf* sbuf)
        : prefix(prefix)
        , sbuf(sbuf)
        , need_prefix(true) {
    }
};

class oprefixstream
    : private virtual prefixbuf
    , public std::ostream
{
public:
    oprefixstream(std::string const& prefix, std::ostream& out)
        : prefixbuf(prefix, out.rdbuf())
        , std::ios(static_cast<std::streambuf*>(this))
        , std::ostream(static_cast<std::streambuf*>(this)) {
    }
};

int main()
{
    oprefixstream out("prefix: ", std::cout);
    out << "hello
"
        << "world
";
}

Stream buffers conceptually keep an internal buffer which is, however, not set up in the example above. Every time there is no space for a character to be written to the output buffer, the virtual function overflow() is called with a character (it may also be called with the special value std::char_traits<char>::eof() which is typically used to flush the buffer). Since there is no buffer, overflow() will be called for every character. All this function does is to see if it needs to write a prefix and, if so, writes the prefix. In case a newline ' ' is written, the function remembers that it needs to write the prefix if another character is written. It then just forwards writing of the character to the underlying stream buffer.

The virtual function sync() is used to synchronize the stream with its external representation. For a stream buffer keeping a buffer it makes sure that any buffer is written. Since the prefixbuf doesn't really keep a buffer, all it needs to is to delegate the sync() request to the underlying stream buffer by calling pubsync().


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...