2013-02-14 39 views
2

我想爲我的類編寫<<運算符,它們通常包含一些結構化數據。最簡單的例子之一是包含一系列矩陣的類,例如使用C++中的流打印正確縮進的結構化對象

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之後使流輸出給定數量的空間?

+0

我認爲你必須創建自己的流包裝類,將輸入流包裝在你的'operator >>'中並使用包裝器來輸出矩陣。 – Angew 2013-02-14 14:54:13

回答

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<<適當Matrix

或者,你可以只使用std::ios_base::xalloc來 獲得一個地方,你可以告訴operator<<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); 
    // ... 
} 

這比過濾streambuf的靈活性要小得多。 特別是,它不能用於您的 不控制operator<<的實現的類型。但它簡單,並且有時也很有用。

(我要說,其實,使用C++的人應該熟悉 有兩種技術,但我不知道任何教程文本 其中甚至提到他們。而在這個世界上,有大量 的C++用戶仍然在寫while (! file.eof()),它的 可能太多要求。)

+0

我會放棄它!它會嵌套這些工作嗎?例如。如果我的Matrix類決定在流上使用你的'IndentingStreambuf'(已經包裝在其中的一箇中),它是否會添加所需的所有縮進(即原始+ Matrix類中的縮進)? – Grzenio 2013-02-14 16:11:16

+0

當我嘗試按照以下方式使用它時,出現了此編譯器錯誤:'/home/ga1009/PhD/cpp/pmi/cpp/src/baumestimates.h:40:5:錯誤:'operator <<'不匹配在'IndentingStreambuf(12u,(*&os))<< BaumEstimates :: distParams()const [int N = 2; int M = 1; int K = 1]()。boost :: shared_ptr :: operator * >>()'' – Grzenio 2013-02-14 16:20:35

+0

@Grzenio它們嵌套很好。另一方面,我如何使用它的例子是完全錯誤的;我不知道我在想什麼。我已經編輯它來修復它。 (而我在做這件事的時候:如果你想嘗試一下,你應該試着理解它,這意味着學習streambuf及其在C++ IO中的作用。) – 2013-02-14 16:48:43