我对C ++语言有些陌生。我正在编写一个用于记录到文件的实用程序类。它工作得很漂亮,除了现在我想通过使它更方便使用(例如将字符串流传递给日志函数)来增强它。
这是我一直在尝试的,但它没有奏效。
定义:
void LogStream( std::stringstream i_Log ){
m_FileHandle << i_Log << std::endl;
}
呼叫:
m_LogObject->LogStream( "MKLBSearchEngine::Search( " << x << ", " << i_Filter << " ) - No Results Found" );
答案 0 :(得分: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()
调用的特殊函数,它接受一个文件名和一个
行号,在时间戳的开头输出它们和时间戳
下一行输出,并缩进所有其他行。过滤
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
。)
答案 1 :(得分:1)
您的设计存在问题。您不希望接受流作为参数,接受字符串,或使您的类表现为流(或两者)。
如果使对象表现为流,则执行以下操作:
m_LogObject << "what to log" << etc;
为此,只需覆盖<<
运算符。
答案 2 :(得分:1)
您的通话应该是
m_LogObject->LogStream( stringstream() << "MKLBSearchEngine::Search( " << x
<< ", " << i_Filter << " ) - No Results Found" );
因为你需要创建你将传递给函数的stringstream对象。
此调用意味着您已经拥有了所需的输出流,因此我还建议您更改类设计以使用operator<<
进行日志记录,除非它已经过载。
答案 3 :(得分: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()
。
答案 4 :(得分:0)
您不能按值传递流对象(因为它们不可复制),因此您需要传递(并存储)引用:
void LogStream(std::stringstream& i_Log){
m_FileHandle << i_Log << std::endl;
}
这可能不会做你期望的事情(它可能会打印一个i_Log的地址,原因相当模糊)。
如果您的意图是从字符串流中取出东西,这可能会做你想要的:
i_Log.get( *m_FileHandle.rdbuf() );
答案 5 :(得分:0)
您正在按值传递std::stringstream
个实例。您希望避免复制并通过引用(或指针)传递它。例如:
void LogStream ( std::stringstream & i_Log ){ m_FileHandle << i_Log << std::endl; }
详细了解C ++ references。