你的解决方案存在几个问题。首先是你通过值传递了
stringstream
,而它不支持复制。你需要使用引用传递。其次,在调用点上,
operator<<
重载的返回值是
ostream&
而不是
stringstream
,由于
stringstream
不是
ostream&
的基类(它反过来),因此你无法用它来初始化
stringstream
(或
stringstream&
)。最后,没有接受
stringstream
作为右参数的
operator<<
,因此在
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()
调用一个名为“特殊函数”的函数来输出文件名、行号和时间戳,并在下一行输出时对所有其他行进行缩进。使用过滤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
编写了一个
<<
。)