std :: stringstream作为参数

Nat*_*ehr 3 c++ parameters logging stringstream

我对C++语言有些新意.我正在编写一个用于记录到文件的实用程序类.它工作得很漂亮,但现在我想通过使它更方便使用来增强它(例如将字符串流传递给日志功能).

这是我一直在尝试的,但它没有奏效.

定义:

void LogStream( std::stringstream i_Log ){ m_FileHandle << i_Log << std::endl; }

呼叫:

m_LogObject->LogStream( "MKLBSearchEngine::Search( " << x << ", " << i_Filter << " ) - No Results Found" );

Jam*_*nze 11

您的解决方案存在一些问题.第一个是你stringstream通过值传递,它不支持复制.你需要参考.第二个是在调用站点,operator<<重载的返回值是ostream&,而不是stringstream,因为 stringstream它不是基类ostream&(它是相反的),你不能用它初始化stringstream(或stringstream&).最后,没有operator<<哪个采用 stringstream右手参数,因此LogStream函数中的语句 不起作用.最后,无论如何,这对用户来说有点尴尬.日志operator<<是非成员,ostream&非const引用作为第一个参数,因此您不能使用临时作为左参数调用它们.(在你的示例调用中,当然,你忘了创建std::ostringstream它;它不会编译,因为没有重载<<需要a char const[]或a char const*作为它的左手操作数.)

几乎所有这些问题都有解决方法.就像是:

void LogStream( std::ostream& text )
{
    std::ostringstream& s = dynamic_cast<std::ostringstream&>(text);
    m_FileHandle << s.str() << std::endl;
}
Run Code Online (Sandbox Code Playgroud)

处理除了最后一个问题之外的所有问题; 最后一个必须由客户端处理,如:

m_LogObject->LogStream( std::ostringstream().flush() << "..." << x );
Run Code Online (Sandbox Code Playgroud)

(调用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;
    }
};
Run Code Online (Sandbox Code Playgroud)

LogStreamer LogStream() { return LogStreamer( m_FileHandle ); }
Run Code Online (Sandbox Code Playgroud)

然后客户端代码可以写:

m_LogObject->LogStream() << "..." << x;
Run Code Online (Sandbox Code Playgroud)

在我自己的代码:日志对象始终单身,呼叫是通过一个宏,它通过__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();
    }
};
Run Code Online (Sandbox Code Playgroud)

(now()当然,该函数返回std::string带有时间戳的a.或者a struct tm,你写了一个<<for tm.)