重载处理std :: endl?

ano*_*non 31 c++ iostream overloading manipulators endl

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

MyStream myStream;
myStream << 1 << 2 << 3 << std::endl << 5 << 6 << std::endl << 7 << 8 << std::endl;
Run Code Online (Sandbox Code Playgroud)

给出输出

[blah]123
[blah]56
[blah]78
Run Code Online (Sandbox Code Playgroud)

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

这里的困难不是逻辑管理,而是检测和重载处理std::endl.有一种优雅的方式来做到这一点?

谢谢!

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

Mar*_*ork 32

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

以下是有效的,因为std :: endl会导致以下情况.

1)在流中添加'\n'.
2)在流上调用flush()
2a)这将调用流缓冲区上的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)
            {}
            ~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;
}

> ./a.out
[blah]123 
[blah]56 
[blah]78
>
Run Code Online (Sandbox Code Playgroud)

  • @potatoswatter:认为我复制了你,这有点自负.不涉及复制.你想出了可能性的描述.我想出了一个解决方案.我们完全独立完成.Guss what:我以前做过这种事:-) (2认同)

Tim*_*mbo 18

您的MyStream类的重载运算符必须设置previous-printed-token-was-endl标志.

然后,如果打印下一个对象,则[blah]可以将其插入其前面.

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

MyStream& operator<<( std::ostream&(*f)(std::ostream&) )
{
    std::cout << f;

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

    return *this;
}
Run Code Online (Sandbox Code Playgroud)

  • 不幸的是,这并没有检测到std :: endl - 它检测到任何没有参数的操纵器.但我想在<<()运算符中你可以将f与std :: endl进行比较,如果它们是同一个东西则进行特殊处理. (3认同)
  • 这不会起作用,因为你永远不能从`ostream`派生出来:格式化插入器被定义为返回一个'ostream&`.即使你覆盖了所有的默认值,仍然存在用户定义的`ostream&operator <<(ostream&,my_type const&).然后`my_stream << my_type(5)<< endl;`调用`operator <<(ostream&,manipulator)`,而不是`operator <<(MyStream&,manipulator)`. (2认同)
  • 这应该有效,除了GCC抱怨"假设强制转换为'std :: basic_ostream <char,std :: char_traits <char >>&(*)(std :: basic_ostream <char,std :: char_traits <char >> && ''来自重载函数'对`f`到`std :: endl`的比较.@Neil:这不会"关闭"任何操纵者; 它们被传递给`std :: cout`并在那里应用. (2认同)