2

我想<<为我的类编写运算符,这些运算符通常包含一些结构化数据。最简单的示例之一是包含矩阵列表的类,例如

stuct MyClass
{
  std::vector<Matrix> m;
}

假设 Matrix 类可以打印自己(使用多行),并且我们不控制这个类。现在我想得到以下输出:

A(0)=[a b
      c d]
A(1)=[e f
      g h]

并且Matrix该类本身输出:

[a b
 c d]

如何配置/更改流或做一些完全不同的事情以使其工作,即使流在每个之后输出给定数量的空格std::endl

4

1 回答 1

1

这实际上是我第一次真正使用过滤streambuf。给定类似的东西:

std::ostream& operator<<( std::ostream& dest,
                          std::vector<Matrix> const& object );

class MyClass
{
    std::vector<Matrix> m;
};

std::ostream& operator<<( std::ostream& dest, MyClass const& object )
{
    //  ...
    {
        //  Scope to control lifetime of the IndentingStreambuf...
        //  Could be (probably should be) in a separate function.
        IndentingStreambuf indent( dest )
        dest << m;
    }
    //  ...
}

在哪里:

class IndentingStreambuf : public std::streambuf
{
    std::streambuf* myDest;
    std::ostream*   myOwner;
    bool            myIsAtStartOfLine;

protected:
    int overflow( int ch )
    {
        if ( myIsAtStartOfLine && ch != EOF && ch != '\n' ) {
            myDest->sputn( "    ", 4 );
        }
        myIsAtStartOfLine = ch == '\n';
        return myDest->sputc( ch );
    }

public:
    IndentingStreambuf( std::streambuf* dest )
        : myDest( dest )
        , myOwner( NULL )
        , myIsAtStartOfLine( true )
    {
    }
    IndentingStreambuf( std::ostream& dest )
        : myDest( dest.rdbuf() )
        , myOwner( &dest )
        , myIsAtStartOfLine( true )
    {
        myOwner->rdbuf( this );
    }
    ~IndentingStreambuf()
    {
        if ( myOwner != NULL ) {
            myOwner->rdbuf( myDest );
        }
    }
};

编辑:

我只是更详细地阅读了您想要的输出。相同的基本IndentingStreambuf工作,但

  1. 您必须对其进行调整以支持任意缩进(作为构造函数的参数),

  2. 初始化myIsAtStartOfLinefalse, 和

  3. 输出后调用它A(i) = [

当然,适当地定义operator<<for Matrix

或者,您可以使用std::ios_base::xalloc获取一个可以告诉operator<<for Matrix缩进的地方。类似于以下内容:

static long& getMatrixIndent( std::ostream& dest )
{
    static int ourIndex = std::ostream::xalloc();
    return dest.iword( ourIndex );
}

class indent
{
    int myIndent;
public:
    indent( int n ) : myIndent( n ) {}
    friend std::ostream& operator<<( std::ostream& dest,
                                     indent const& manip )
    {
        getMatrixIndent( dest ) = myIndent;
    }
};

std::ostream& operator<<( std::ostream& dest, Matrix const& object )
{
    int indent = getMatrixIndent( dest );
    //  ...
}

这远不如过滤流缓冲区灵活。特别是,它不能用于您不控制operator<<. 但它很简单,有时也很有用。

(事实上​​,我认为任何使用 C++ 的人都应该熟悉这两种技术。但我不知道有任何教程文本甚至提到了它们。而且在一个大量 C++ 用户仍在编写的世界中while ( ! file.eof() ),这可能要求太多了。)

于 2013-02-14T15:04:20.420 回答