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.为什么这个?
修改行为的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().