带前缀的C++ cout

vol*_*ssa 0 c++ iostream cout ostream

我想要一个带有前缀的ostream,在cout上重定向的每一行的开头; 我试试这个:

#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";
}
Run Code Online (Sandbox Code Playgroud)

但我有输出

prefix a
b
Run Code Online (Sandbox Code Playgroud)

没有c.为什么这个?

Die*_*ühl 7

修改行为​​的std::ostream方式不是重载任何输出操作符!相反,您从中派生类std::streambuf并覆盖virtual函数overflow()sync().在你的情况下,你可能会创建一个过滤流缓冲区,即你将另一个std::streambuf作为参数,并以某种方式修改的字符串流写入此流缓冲区.

这是一个简单的例子:

#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";
}
Run Code Online (Sandbox Code Playgroud)

流缓冲区在概念上保留一个内部缓冲区,但是在上面的示例中没有设置.每次没有空格将字符写入输出缓冲区时,都会使用字符调用该virtual函数overflow()(也可以使用std::char_traits<char>::eof()通常用于刷新缓冲区的特殊值调用该函数).由于没有缓冲区,overflow()将为每个字符调用.所有这个功能的作用是看它是否需要写一个前缀,如果是,写入prefix.如果'\n'写入换行符,该函数会记住它需要写入prefixif另一个字符.然后它只是将字符写入底层流缓冲区.

virtual函数sync()用于将流与其外部表示同步.对于保持缓冲区的流缓冲区,它确保写入任何缓冲区.由于prefixbuf并没有真正保留缓冲区,所以它需要sync()通过调用将请求委托给底层流缓冲区pubsync().