重载处理的std :: endl?

我想定义一个类MyStream以便:

 MyStream myStream; myStream << 1 << 2 << 3 << std::endl << 5 << 6 << std::endl << 7 << 8 << std::endl; 

给出输出

 [blah]123 [blah]56 [blah]78 

基本上,我想在前面插入一个“[blah]”,然后在每个非终止 std::endl之后插入?

这里的难点不是逻辑pipe理,而是检测和重载std::endl的处理。 有没有一个优雅的方式来做到这一点?

谢谢!

编辑:我不需要在逻辑pipe理的build议。 我需要知道如何检测/超载打印std::endl

你需要做的是写你自己的stream缓冲区:
在刷新stream缓冲区时,输出前缀字符和stream的内容。

下面的工作,因为std :: endl导致以下。

1)将“\ n”添加到stream中。
2)在stream上调用flush()
2a)这将调用stream缓冲区上的pubsync()。
2b)这调用了虚拟方法sync()
2c)重写这个虚拟方法来完成你想要的工作。

 #include <iostream> #include <sstream> class MyStream: public std::ostream { // Write a stream buffer that prefixes each line with Plop class MyStreamBuf: public std::stringbuf { std::ostream& output; public: MyStreamBuf(std::ostream& str) :output(str) {} // When we sync the stream with the output. // 1) Output Plop then the buffer // 2) Reset the buffer // 3) flush the actual output stream we are using. virtual int sync ( ) { output << "[blah]" << str(); str(""); output.flush(); return 0; } }; // My Stream just uses a version of my special buffer MyStreamBuf buffer; public: MyStream(std::ostream& str) :std::ostream(&buffer) ,buffer(str) { } }; int main() { MyStream myStream(std::cout); myStream << 1 << 2 << 3 << std::endl << 5 << 6 << std::endl << 7 << 8 << std::endl; } > ./a.out [blah]123 [blah]56 [blah]78 > 

你的MyStream类的重载操作符必须设置一个先前打印的token-was-endl标志。

然后,如果下一个对象被打印, [blah]可以被插入到它的前面。

std::endl是一个函数,它返回一个对std::ostream的引用。 要检测到它被转移到你的stream中,你必须重载operator<<你的types和这样一个函数之间:

 MyStream& operator<<( std::ostream&(*f)(std::ostream&) ) { std::cout << f; if( f == std::endl ) { _lastTokenWasEndl = true; } return *this; } 

原则上同意尼尔。

你想改变缓冲区的行为,因为这是扩展iostreams的唯一方法。 endl是这样做的:

 flush(__os.put(__os.widen('\n'))); 

widen返回单个字符,所以你不能把你的string在那里。 put调用putc这不是一个虚函数,只是偶尔挂钩overflow 。 您可以在flush拦截,调用缓冲区的sync 。 您将需要截取并更改所有换行符,因为它们overflow或手动sync并将其转换为您的string。

devise一个覆盖缓冲区是很麻烦的,因为basic_streambuf需要直接访问它的缓冲区。 这可以防止您轻松地将I / O请求传递给已有的basic_streambuf 。 你需要走出去,假设你知道stream缓冲类,并从中得出。 ( cincout不保证使用basic_filebuf ,据我所知)。然后,只需添加virtual overflowsync 。 (见第27.5.2.4.5 / 3和27.5.2.4.2 / 7)。进行替代可能需要额外的空间,所以要小心提前分配。

– 要么 –

只要在自己的命名空间中声明一个新的endl ,或者更好的是一个根本就不叫做endl的操纵器!

而不是试图修改std::endl的行为,你应该创build一个过滤streambuf做这个工作。 詹姆斯Kanze有一个例子显示如何在每个输出行的开始插入一个时间戳。 它只需要稍作修改就可以将其更改为每行所需的任何前缀。

我使用函数指针。 对于不熟悉C的人来说听起来很可怕,但在大多数情况下,效率会更高。 这是一个例子:

 #include <iostream> class Foo { public: Foo& operator<<(const char* str) { std::cout << str; return *this; } // If your compiler allows it, you can omit the "fun" from *fun below. It'll make it an anonymous parameter, though... Foo& operator<<(std::ostream& (*fun)(std::ostream&)) { std::cout << std::endl; } } foo; int main(int argc,char **argv) { foo << "This is a test!" << std::endl; return 0; } 

如果你真的想要你可以检查endl的地址,以确认你没有得到一些其他的无效/无效function,但我认为这在大多数情况下是不值得的。 我希望有帮助。

你不能改变std::endl – 因为它的名字暗示它是C ++标准库的一部分,它的行为是固定的。 当它接收到行结束时,您需要更改stream本身的行为。 就个人而言,我不会认为这是值得的努力,但如果你想冒险进入这个领域,我强烈build议阅读本书的标准C + + IOStreams和语言环境 。

Interesting Posts