首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >性病的过载处理::endl?

性病的过载处理::endl?
EN

Stack Overflow用户
提问于 2010-02-06 10:17:27
回答 7查看 14.7K关注 0票数 36

我想要定义一个类MyStream,以便:

代码语言:javascript
复制
MyStream myStream;
myStream << 1 << 2 << 3 << std::endl << 5 << 6 << std::endl << 7 << 8 << std::endl;

给予输出

代码语言:javascript
复制
[blah]123
[blah]56
[blah]78

基本上,我希望在前面插入一个"blah“,然后在每个不终止的std::endl之后插入。

这里的困难不是逻辑管理,而是检测和重载std::endl的处理。有什么优雅的方法吗?

谢谢!

编辑:我不需要关于逻辑管理的建议。我需要知道如何检测/过载打印std::endl

EN

回答 7

Stack Overflow用户

回答已采纳

发布于 2010-02-06 11:38:14

您需要做的是编写您自己的流缓冲区:当流缓冲区被刷新时,您需要输出前缀字符和流的内容。

以下操作是因为std::endl导致以下情况。

  1. '\n'添加到流中。
  2. 调用流上的flush()
  3. 这将调用流缓冲区上的pubsync()
代码语言:javascript
复制
1. This calls the virtual method `sync()`
2. Override this virtual method to do the work you want.
代码语言:javascript
复制
#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)
            {}
            ~MyStreamBuf() {
                if (pbase() != pptr()) {
                    putOutput();
                }
            }
   
        // 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() {
            putOutput();
            return 0;
        }
        void putOutput() {
            // Called by destructor.
            // destructor can not call virtual methods.
            output << "[blah]" << str();
            str("");
            output.flush();
        }
    };

    // 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;
}
代码语言:javascript
复制
> ./a.out
[blah]123 
[blah]56 
[blah]78
>
票数 35
EN

Stack Overflow用户

发布于 2010-02-06 10:20:01

MyStream类的重载运算符必须设置一个以前打印的令牌即endl标志。

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

std::endl是一个函数,接受并返回对std::ostream的引用。要检测它被转移到您的流中,您必须在您的类型和这样一个函数之间重载operator<<

代码语言:javascript
复制
MyStream& operator<<( std::ostream&(*f)(std::ostream&) )
{
    std::cout << f;

    if( f == std::endl )
    {
        _lastTokenWasEndl = true;
    }

    return *this;
}
票数 18
EN

Stack Overflow用户

发布于 2010-02-06 11:30:02

在原则上同意尼尔的观点。

您希望更改缓冲区的行为,因为这是扩展iostreams的唯一方法。endl这样做:

代码语言:javascript
复制
flush(__os.put(__os.widen('\n')));

widen返回一个字符,因此不能将字符串放在其中。put调用putc,这不是一个虚拟函数,只是偶尔与overflow挂钩。您可以在flush拦截,后者调用缓冲区的sync。您需要截取和更改所有换行符,因为它们是overflow编辑的或手动的synced,并将它们转换为您的字符串。

设计一个覆盖缓冲区类很麻烦,因为basic_streambuf希望直接访问它的缓冲区内存。这使您无法轻松地将I/O请求传递给预先存在的basic_streambuf。您需要跳出一个分支,假设您知道流缓冲区类,并从中派生出来。(据我所知,cincout不能保证使用basic_filebuf。)然后,只需添加virtual overflowsync。(见第27.5.2.4.5/3和27.5.2.4.2/7节)执行替换可能需要额外的空间,所以要小心提前分配。

-或-

只需在您自己的名称空间中声明一个新的endl,或者更好的是,一个根本不称为endl的操作器!

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/2212776

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档