C++ cout with prefix

后端 未结 4 1651
醉话见心
醉话见心 2021-01-07 14:15

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

#include 
#include 
class paralle         


        
相关标签:
4条回答
  • 2021-01-07 14:47

    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;
    }
    
    0 讨论(0)
  • 2021-01-07 14:59

    Alternatively you could write a function though the syntax changes.

    template<typename T>
    void print(T content)
    {
        cout<<whatever your prefix is;
        cout<<content;
    }
    
    0 讨论(0)
  • 2021-01-07 15:05

    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().

    0 讨论(0)
  • 2021-01-07 15:09

    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";
    }
    
    0 讨论(0)
提交回复
热议问题