我对C++语言有些陌生。我正在编写一个用于记录到文件的实用程序类。它工作得很好,除了现在我想通过使它更易于使用来增强它(例如,将字符串流传递给一个日志函数)。
这就是我一直在尝试的,但没有奏效。
定义:
void LogStream( std::stringstream i_Log ){ m_FileHandle << i_Log << std::endl; }
呼叫:
m_LogObject->LogStream( "MKLBSearchEngine::Search( " << x << ", " << i_Filter << " ) - No Results Found" );
发布于 2011-06-08 23:51:11
您的解决方案有几个问题。第一个是按值传递stringstream,它不支持复制。您需要通过引用。第二个问题是,在调用站点,operator<<重载的返回值是ostream&,而不是stringstream,而且由于stringstream不是ostream&的基类(相反),因此不能用它初始化stringstream (或stringstream&)。最后,没有将stringstream作为右手参数的operator<<,因此LogStream函数中的语句无法工作。最后,这对用户来说无论如何都会有些尴尬。operator<<的日志是非成员,使用ostream&非常数引用作为第一个参数,所以您不能使用临时作为左参数来调用它们。(当然,在您的示例调用中,您忘了创建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()的调用将返回对流的非常数引用,该引用可用于初始化进一步的std::ostream&。虽然不能用临时变量初始化非常数引用,但可以在其上调用非常数成员函数。)
对于客户端代码来说,这一点的笨拙使我通常更喜欢更复杂的解决方案。我定义了一个特殊的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()调用,它接受文件名和行号,在下一行输出的开始处输出它们和时间戳,并缩进所有其他行。一个过滤streambuf,包含如下内容:
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编写了<<。)
发布于 2011-06-08 22:21:51
你的设计有问题。你不想接受一个流作为参数,或者接受一个字符串,或者让你的类表现为一个流(或者两者兼而有之)。
如果使对象行为类似于流,则执行以下操作:
m_LogObject << "what to log" << etc;为此,只需覆盖<<操作符。
发布于 2011-06-08 22:26:54
您的呼叫应如下所示
m_LogObject->LogStream( stringstream() << "MKLBSearchEngine::Search( " << x
<< ", " << i_Filter << " ) - No Results Found" );因为您需要创建将传递给函数的stringstream对象。
这个调用意味着您已经有了所需的输出流,所以我还建议您更改类设计,以便使用operator<<进行日志记录,除非它已经超载。
https://stackoverflow.com/questions/6280149
复制相似问题