2017-04-26 35 views
-1

所以,我開始了一個縮進緩衝區/ ostream,使用操縱器設置縮進級別並遇到問題......第一個是編譯器錯誤 indent_ostream& increase(indent_ostream&)' will always evaluate as 'true'。只是將函數指針作爲運算符< <作爲ostream的成員。接下來是ambiguous overload for 'operator<<' (operand types are 'indent_ostream' and 'int')。還增加了一個成員operator < <與模板參數來捕獲所有類型進行流(字符串,整數等)。該結果爲Segmentation fault,在這裏我:(派生自streambuf,ostream和manip - 沒有編譯或崩潰

#include <iostream> 
#include <streambuf> 
#include <iomanip> 

class indent_sbuf : public std::streambuf 
{ 
    std::streambuf*  m_sbuf; 
    std::string   m_indent_str; 
    bool    m_start_of_line; 
    static const int TAB_WIDTH = 4; 

public: 
    explicit indent_sbuf(std::streambuf* sbuf, size_t indent = 0) 
     : m_sbuf{ sbuf } 
     , m_indent_str(indent, ' ') 
     , m_start_of_line{ true } 
    { } 

    ~indent_sbuf() 
    { 
     overflow('\n'); 
    } 

    indent_sbuf& increase() 
    { 
     m_indent_str = std::string(m_indent_str.size() + TAB_WIDTH, ' '); 
     return *this; 
    } 

    indent_sbuf& decrease() 
    { 
     if(m_indent_str.size() > TAB_WIDTH) { 
      m_indent_str = std::string(m_indent_str.size() - TAB_WIDTH, ' '); 
     } 
     else { 
      m_indent_str = ""; 
     } 
     return *this; 
    } 

private: 
    int_type overflow(int_type chr) override 
    { 
     if (m_start_of_line && chr != '\n') { 
      m_sbuf->sputn(m_indent_str.data(), m_indent_str.size()); 
     } 
     m_start_of_line = (chr == '\n'); 
     return m_sbuf->sputc(chr); 
    } 
}; 

class indent_ostream : public std::ostream 
{ 
    indent_sbuf buf; 

public: 
    indent_ostream(std::ostream& os, size_t width) 
     : std::ostream(&buf) 
     , buf(os.rdbuf(), width) 
    { } 

    indent_ostream& operator<<(indent_ostream& (*fcn)(indent_ostream&)) 
    { 
     return (*fcn)(*this); 
    } 

    template<typename T> 
    indent_ostream& operator<<(T const& v) // get it to compile 
    { 
     *this << v; // but crash 
     return *this; 
    } 
}; 

static inline 
indent_ostream& increase(indent_ostream& os) 
{ 
    indent_sbuf* buf = static_cast<indent_sbuf*>(os.rdbuf()); 
    buf->increase(); 
    return os; 
} 

static inline 
indent_ostream& decrease(indent_ostream& os) 
{ 
    indent_sbuf* buf = static_cast<indent_sbuf*>(os.rdbuf()); 
    buf->decrease(); 
    return os; 
} 


int main() 
{ 
    indent_ostream os(std::cout, 0); 
    os << "Hallo\n"; 
    os << increase << "World\n"; 
    os << decrease << 42 << "\n"; 
} 

此外,在coliru。那麼,是什麼會在這裏和那裏是我的缺點如何得到它的工作正確的,符合標準的

+5

良好的經驗法則:如果您收到一條警告,您不明白,請不要匆匆離開您的代碼以使其消失。嘗試瞭解警告。 – Barry

+2

^您可以通過修復編譯器檢測到的問題或者通過對編譯器合理地檢測問題進行檢測來消除編譯器警告。摧毀代碼直到「有效」更有可能導致第二個問題,而不是先嚐試理解代碼。 – jaggedSpire

+0

@jaggedSpire但在SO *上傾銷了一堆代碼確實*工作...有人是**肯定**來一起並提供答案。 –

回答

3

所以你得到了一個警告:??

首先是編譯器錯誤indent_ostream& increase(indent_ostream&)'將始終評估爲「真」

爲什麼?那是什麼意思? os << increase實際上做了什麼?不要忽視警告!它指出你在代碼中有一個真正的問題!調查!

如果您在運營商operator<<的名單看,有這樣一句:

basic_ostream& operator<<(
    std::basic_ostream<CharT,Traits>& (*func)(std::basic_ostream<CharT,Traits>&)); 

但一個不匹配你的函數,它不是一個可行的候選者。功能Derived&(*)(Derived&)Base&(*)(Base&)不匹配 - 它無法工作。因此,最好的(唯一的)可行的候選人是:

basic_ostream& operator<<(bool value); 

因爲函數指針可以轉換爲bool。警告的是,這很愚蠢,因爲顯然這將打印1,可能不是你想要做的。

但是,您實際上並不需要需要函數採取indent_ostream無論如何。你所關心的只是緩衝區。所以解決方案是修復您的修改器以匹配預期的簽名:

static inline std::ostream& increase(std::ostream& os) 
{ 
    indent_sbuf* buf = static_cast<indent_sbuf*>(os.rdbuf()); 
    buf->increase(); 
    return os; 
} 

static inline std::ostream& decrease(std::ostream& os) 
{ 
    indent_sbuf* buf = static_cast<indent_sbuf*>(os.rdbuf()); 
    buf->decrease(); 
    return os; 
} 

現在,它的工作原理!

+0

澄清:我沒有忽視警告。但是我的結論在哪裏是不同的和虛假快速搜索也得到了點布爾轉換。 Josutties Std C++ Lib書籍章節「操縱器如何工作」顯示了操作符<<(...(* op)(..))過載。因此,我的經驗,這必須失蹤。錯誤的結論...爲什麼我寫增加(indent_ostream&..)的原因是爲了避免劫持std :: ostream,因爲底層緩衝區沒有增加成員函數。這樣奇蹟就開始了。 – Olx

+0

無論如何,很好的解釋,但我仍然不明白爲什麼分段故障 - 即使(imo)運算符<<(indent_ostream&..)是更可行的運算符<<(T const&)操縱符? – Olx

+0

@Olx唔......你在什麼時候將'streambuf'的重寫放入'cout'? – Barry