2011-06-08 87 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。)

相关问题