首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >std::stringstream作为参数

std::stringstream作为参数
EN

Stack Overflow用户
提问于 2011-06-08 22:15:13
回答 6查看 9.1K关注 0票数 4

我对C++语言有些陌生。我正在编写一个用于记录到文件的实用程序类。它工作得很好,除了现在我想通过使它更易于使用来增强它(例如,将字符串流传递给一个日志函数)。

这就是我一直在尝试的,但没有奏效。

定义:

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

呼叫:

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

EN

回答 6

Stack Overflow用户

发布于 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*作为其左操作数的<<。)

几乎所有这些问题都有解决方法。类似于:

代码语言:javascript
复制
void LogStream( std::ostream& text )
{
    std::ostringstream& s = dynamic_cast<std::ostringstream&>(text);
    m_FileHandle << s.str() << std::endl;
}

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

代码语言:javascript
复制
m_LogObject->LogStream( std::ostringstream().flush() << "..." << x );

(对std::ostream::flush()的调用将返回对流的非常数引用,该引用可用于初始化进一步的std::ostream&。虽然不能用临时变量初始化非常数引用,但可以在其上调用非常数成员函数。)

对于客户端代码来说,这一点的笨拙使我通常更喜欢更复杂的解决方案。我定义了一个特殊的LogStreamer类,类似于:

代码语言:javascript
复制
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;
    }
};

代码语言:javascript
复制
LogStreamer LogStream() { return LogStreamer( m_FileHandle ); }

然后,客户端代码可以这样写:

代码语言:javascript
复制
m_LogObject->LogStream() << "..." << x;

在我自己的代码中:日志对象总是单例的,调用是通过一个宏,它将__FILE____LINE__传递给LogStream()函数,而最终的目标ostream是一个特殊的streambuf,它有一个特殊的函数,由LogStream()调用,它接受文件名和行号,在下一行输出的开始处输出它们和时间戳,并缩进所有其他行。一个过滤streambuf,包含如下内容:

代码语言:javascript
复制
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编写了<<。)

票数 11
EN

Stack Overflow用户

发布于 2011-06-08 22:21:51

你的设计有问题。你不想接受一个流作为参数,或者接受一个字符串,或者让你的类表现为一个流(或者两者兼而有之)。

如果使对象行为类似于流,则执行以下操作:

代码语言:javascript
复制
m_LogObject << "what to log" << etc;

为此,只需覆盖<<操作符。

票数 1
EN

Stack Overflow用户

发布于 2011-06-08 22:26:54

您的呼叫应如下所示

代码语言:javascript
复制
m_LogObject->LogStream( stringstream() << "MKLBSearchEngine::Search( " << x
 << ", " << i_Filter << " ) - No Results Found" );

因为您需要创建将传递给函数的stringstream对象。

这个调用意味着您已经有了所需的输出流,所以我还建议您更改类设计,以便使用operator<<进行日志记录,除非它已经超载。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/6280149

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档