Есть несколько проблем с вашим решением. Во-первых, ты
передача stringstream
по значению, и он не поддерживает копирование. Тебе нужно
по ссылке. Во-вторых, на сайте вызова возвращаемое значение
operator<<
перегрузки ostream&
, а не stringstream
, и с
stringstream
не является базовым классом ostream&
(это другой способ
раунд), вы не можете инициализировать stringstream
(или stringstream&
)
с этим. И, наконец, нет operator<<
, который занимает
stringstream
как параметр правой руки, поэтому оператор в
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 - это специальный потоковый буфер с
специальная функция, вызываемая 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
.)