2011-06-08 82 views
3

我對C++語言有點新鮮。我正在編寫一個實用程序類來記錄文件。除了現在我想通過使它更便於使用(例如,將字符串流傳遞到日誌函數)來增強它以外,它的工作原理非常漂亮。std :: stringstream作爲參數

這是我一直在嘗試,它沒有奏效。

定義:

void LogStream(std::stringstream i_Log){ m_FileHandle << i_Log << std::endl; }

電話:

m_LogObject->LogStream("MKLBSearchEngine::Search(" << x << ", " << i_Filter << ") - No Results Found");

+3

什麼不起作用?錯誤,錯誤的行爲? – 2011-06-08 14:21:35

回答

0

不能按值傳遞流對象(因爲它們是不可拷貝),所以你需要通過傳遞(和商店)參考:

void LogStream(std::stringstream& i_Log){ 
    m_FileHandle << i_Log << std::endl; 
} 

這可能不會做你期望的事情(它可能會打印一個i_Log的地址,因爲比較模糊的原因)。

如果你的目的是把東西都拿了出來stringstream的,這可能會做你想要什麼:

i_Log.get(*m_FileHandle.rdbuf()); 
+0

這是無關緊要的:-D正確地閱讀問題。 – 2011-06-08 14:19:24

+0

@Let_Me_Be這並非無關緊要,正確閱讀答案! – 2011-06-08 14:33:13

+0

@Christian它是,它不會工作,因爲你需要通過不斷的參考來工作。而且,它仍不能解決更大的問題。 – 2011-06-08 14:34:08

0

你是按值傳遞std::stringstream實例。您希望避免複製並通過引用(或指針)傳遞它。例如:

void LogStream (std::stringstream & i_Log){ m_FileHandle << i_Log << std::endl; } 

瞭解更多關於C++ references

+0

這是無關緊要的:-D正確地閱讀問題。 – 2011-06-08 14:19:01

1

您的設計有問題。你不想接受一個流作爲參數,要麼接受一個字符串,要麼讓你的類表現爲一個流(或兩者)。

如果你讓你的對象表現爲流,那麼你做到以下幾點:

m_LogObject << "what to log" << etc; 

要做到這一點,只需重寫<<操作。

+1

爲什麼這比你被批評爲無關緊要的兩個答案更相關?使用流作爲參數有什麼問題? – Duck 2011-06-08 14:26:32

+0

因爲它不能以你想要的方式使用。它不會工作。你可以做的是傳遞常量引用,然後你必須通過'stringstream()'預先設置參數,這並不方便。 – 2011-06-08 14:30:46

+0

也許我誤解了這個,但看起來錯誤的是OP對LogStream的調用全部搞砸了。那是他傳球的一根弦?對如何創建一個stringstream有些誤解?無論如何,如果他展示瞭如何正確創建stringstream並通過它來回答他的問題。 – Duck 2011-06-08 14:43:38

1

您的電話應該像

m_LogObject->LogStream(stringstream() << "MKLBSearchEngine::Search(" << x 
<< ", " << i_Filter << ") - No Results Found"); 

,因爲你需要創建一個你會被傳遞給函數的stringstream的對象。

這個調用意味着你已經有一個期望的輸出流,所以我也建議你改變你的類設計,使用operator<<進行日誌記錄,除非它已經超載。

1

您的函數調用將不起作用,因爲"MKLBSearchEngine::Search("的類型爲const char *並且對於<<運算符沒有超載。它不會與std::string("MKLBSearchEngine::Search(")一起使用,因爲std::string也沒有這樣的操作符。你可以做的是用std::stringstream("MKLBSearchEngine::Search(")來調用它,它將第一個參數轉換爲流,以便下面的操作符在這個流上工作。但正如其他人指出的那樣,您必須將函數參數設爲const引用,因爲流不可複製(即使這樣做效率也不高)。另外,只要在文件中寫入std::stringstream將不會做你想要的(如果它工作正常),而不得不採取其內容(底層std::string)。因此,所有的所有的代碼應該是這樣的:

void LogStream(const std::stringstream &i_Log){ m_FileHandle << i_Log.str() << std::endl; } 
... 
m_LogObject->LogStream(std::stringstream("MKLBSearchEngine::Search(") << x << ", " << i_Filter << ") - No Results Found"); 

但你也可以只使用一個LogString(const std::string &),讓這個函數調用stream.str()自己的用戶。

11

您的解決方案有幾個問題。首先是你 按值通過stringstream,它不支持複製。您需要 作爲參考。第二個是在調用點的 的operator<<重載返回值ostream&,不stringstream,由於 stringstream不是一個基類的ostream&(這是其他方式 輪),你不能初始化stringstream(或stringstream&) 與它。最後,沒有operator<<需要 stringstream作爲右手參數,因此 LogStream函數中的語句無法工作。最後,無論如何,這對用戶來說會有些尷尬。 operator<<的日誌是非成員, 與ostream&非const引用作爲第一個參數,所以您不能用 作爲臨時參數調用它們作爲左參數。 (在你的榜樣通話,當然 ,你忘了反正創建std::ostringstream;它 不會編譯,因爲不存在<<超載,這需要char const[]char const*作爲其左操作數。)

有幾乎是解決所有這些問題的解決方法。東西 喜歡:

void LogStream(std::ostream& text) 
{ 
    std::ostringstream& s = dynamic_cast<std::ostringstream&>(text); 
    m_FileHandle << s.str() << std::endl; 
} 

處理所有的除了最後的問題;最後必須由客戶端來處理 ,是這樣的:

m_LogObject->LogStream(std::ostringstream().flush() << "..." << x); 

(以std::ostream::flush()調用返回非const引用 流,可用於初始化進一步std::ostream& 而當你。不能初始化一個臨時的非const引用, 你可以調用它的非const成員函數)。

的這個客戶端代碼中的尷尬讓我一般喜歡 更復雜的解決方案。我定義了一個特殊的LogStreamer類, 是這樣的:

class LogStreamer 
{ 
    boost::shared_ptr<std::ostream> m_collector; 
    std::ostream* m_dest; 

public: 
    LogStreamer(std::ostream& dest) 
     , m_collector(new std::ostringstream) 
     , m_dest(&dest) 
    { 
    } 
    ~LogStreamer() 
    { 
     if (m_collector.unique()) { 
      *m_dest << m_collector->str() << std::endl; 
     } 
    } 
    template <typename T> 
    LogStreamer& operator<<(T const& value) 
    { 
     *m_collector << value; 
     return *this; 
    } 
}; 

LogStreamer LogStream() { return LogStreamer(m_FileHandle); } 

,客戶端代碼可以寫:

m_LogObject->LogStream() << "..." << x; 

在我自己的代碼:日誌對象始終是一個單身人士,電話是 通過一個宏,它通過__FILE____LINE__LogStream() 函數,並且最終目標ostream是一個特殊的streambuf,具有 特殊功能,由LogStream()調用,它接受一個文件名和一個 行號,將它們連同時間戳一起輸出到 的下一行輸出,並縮進所有其他行。一種過濾 流緩衝的東西,如:

class LogFilter : public std::streambuf 
{ 
    std::streambuf* m_finalDest; 
    std::string m_currentHeader; 
    bool m_isAtStartOfLine; 
protected: 
    virtual int overflow(int ch) 
    { 
     if (m_isAtStartOfLine) { 
      m_finalDest->sputn(m_currentHeader.data(), m_currentHeader.size()); 
      m_currentHeader = " "; 
     } 
     m_isAtStartOfLine = (ch == '\n'); 
     return m_finalDest->sputc(ch); 
    } 
    virtual int sync() 
    { 
     return m_finalDest->sync(); 
    } 

public: 
    LogFilter(std::streambuf* dest) 
     : m_finalDest(dest) 
     , m_currentHeader("") 
     , m_isAtStartOfLine(true) 
    { 
    } 
    void startEntry(char const* filename, int lineNumber) 
    { 
     std::ostringstream header; 
     header << now() << ": " << filename << " (" << lineNumber << "): "; 
     m_currentHeader = header.str(); 
    } 
}; 

(功能now(),當然,返回std::string與 時間戳或一個struct tm,你已經寫了一個<<tm。)

相關問題