1

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\nb"<<"c\n";
}

but i have in output

prefix a
b

without c. why this?

volperossa
  • 1,339
  • 20
  • 33
  • In general, it is not a good idea to derive from std::stream - it doesn't have a virtual destructor, and your code shows how output operations don't really work on the derived class, because you are returning a reference to the base class. I'll try to expand to a full answer, unless somebody beats me to it :) – Martin Prazak Dec 06 '14 at 20:52
  • 2
    Your template should return `parallel_cout&`, not generic `ostream&`. – Deduplicator Dec 06 '14 at 20:52
  • 2
    @martin_pr `std::ostream` has a virtual constructor (inherited from `std::ios_base`). Also, `std::fstream` and `std::stringstream` are also derived classes, but they work fine. The main reason why you would want to derive from a IOStreams base class is to wrap around a custom `std::streambuf`, which is what the concrete stream classes do. – David G Dec 06 '14 at 20:54
  • @499602D2 Fair enough, my bad. – Martin Prazak Dec 06 '14 at 20:55
  • In fact, this code shouldn't even compile as `std::ostream` doesn't have a default-constructor and you haven't initialized it in the initializer list. On clang with [libc++](http://coliru.stacked-crooked.com/a/d059c7a2e4c9f840) you get a segmentation fault. – David G Dec 06 '14 at 20:59
  • @Deduplicator you're right!thanks!it works..I have just problems with std::endl after << that makes no match for operator<< error – volperossa Dec 06 '14 at 21:00
  • 1
    @volperossa: you should really **not** use the approach using templates! The use of manipulators like `std::endl` also won't be the end of your problems: when passing you stream to a function taking a `std::ostream&` it will also not do the Right Thing. Using a custom stream buffer _will_ do the Right Thing both for manipulators as well as when passing the stream stream to function taking an `std::ostream&`. That said: the problem with manipulators is that they are function templates and `std::ostream` has a suitable output operator which is used to deduce the template arguments. – Dietmar Kühl Dec 06 '14 at 21:34

4 Answers4

9

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 == '\n';
        }
        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\n"
        << "world\n";
}

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 '\n' 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().

Dietmar Kühl
  • 150,225
  • 13
  • 225
  • 380
  • I don't know about these methods (sync and overflow) do you know a good tutorial? – volperossa Dec 06 '14 at 21:21
  • 1
    The IOStreams library is explained in Nicolai Josuttis's "The C++ Standard library" and, obviously, the explanation is _excellent_ (I may be bias, though, having written in particular the original version of the sections on creating stream buffers). There is also Angelika Langer and Klaus Kreft's "IOStreams and Locales" but this is an entire book just devoted to I/O. Otherwise, if you look on Google for "streambuf" and either "James Kanze" or "Dietmar Kuehl" you should find plenty of resources. – Dietmar Kühl Dec 06 '14 at 21:25
  • Dear Dietmar, what is the visibility class (`public`/`protected`/`private`) in the above examples? In Nicolai's book, the custom streambuffer example assigns `protected` to the `overflow` method and leaves out the sync. – shuhalo Sep 12 '18 at 18:20
  • @shuhalo: the `prefixbuf` isn’t intended to be inherited from. Thus, it doesn’t really matter whether `prefixbuf` is `protected` or `private`. When I wrote above code I was probably too lazy to put in `protected` before `overflow()`: if `prefixbuf` is inherited from for whatever reason it may be useful to make `prefixbuf::overflow()` accessible to the derived class. If I forget `sync()` in Nico’s book for a filtering stream buffer for output I made an error and NIco didn’t correct it when he integrated it into his book: on which example is that? – Dietmar Kühl Sep 12 '18 at 22:13
  • I have read Chapter 13.13.3 in "The C++ Standard library" prior to coming to this thread (21st printing, 2008). Hope this helps. Thanks for the quick reply by the way. – shuhalo Sep 13 '18 at 06:09
  • [example usage in a class](https://github.com/milahu/random/blob/master/cc/print-lines-with-prefix/main.cc) – milahu Jul 05 '22 at 09:49
  • fix warning: `(long unsigned int) this->sbuf->sputn` – milahu Jul 05 '22 at 10:11
3

As Dietmar said, what you want is your own streambuf, something on this general order:

#include <streambuf>
#include <iostream>

class prefixer: public std::streambuf {
public:
    prefixer(std::streambuf* s): sbuf(s) {}
    ~prefixer() { overflow('\n'); }
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':  {
            prefix = "[FIX]";
            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();
            return rc;
        }
        default:
            buffer += c;
            return c;
        }
    }

    std::string prefix;
    std::streambuf* sbuf;
    string buffer;
};

To use this, you create an instance of it from some other streambuf (that defines where it's going to write to) and then (usually) create an ostream using this streambuf. Then you can write to that ostream, and your prefix gets written to each line of output. For example:

int main() { 
    prefixer buf(std::cout.rdbuf());

    std::ostream out(&buf);

    out << "Test\n";
}
Jerry Coffin
  • 476,176
  • 80
  • 629
  • 1,111
  • Nice effort although I prefer my version: for one I think it is simpler and for another it doesn't create a trailing prefix after the last newline. It also prefixes the first line without a spurious newline. Finally, it passes through the flush to the underlying stream buffer. I realize that your version is buffered but without flushing upon `sync()` that's causing some harm. My version isn't buffered for simplicity although I realize that not buffering stream buffers introduces a potential performance problem. – Dietmar Kühl Dec 06 '14 at 21:22
1

Alternatively you could write a function though the syntax changes.

template<typename T>
void print(T content)
{
    cout<<whatever your prefix is;
    cout<<content;
}
j_v_wow_d
  • 511
  • 2
  • 11
0

Your output operator is returning a reference to the base class (std::ostream), which means that the next call to operator << will not use your implementation.

Changing your output operator to this should fix your problem:

template <typename T>
parallel_cout& operator<< (const T& val)
{
    out << "prefix " << val;
    return *this;
}
Deduplicator
  • 44,692
  • 7
  • 66
  • 118
Martin Prazak
  • 1,476
  • 12
  • 20