重载处理的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缓冲类,并从中得出。 ( cin
和cout
不保证使用basic_filebuf
,据我所知)。然后,只需添加virtual overflow
和sync
。 (见第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和语言环境 。