stringstream/osstream 未链接 << 运算符且从不在 std::end 调用刷新的问题

Issue with stringstream/osstream not chaining << operator and never calling flush at std::end

所以我有以下记录class

#include <iostream>
#include <iomanip>
#include <sstream>
#include <string>

struct asDigest {
    explicit asDigest(const void* text, size_t len) : _t(text), _l(len) {}
    explicit asDigest(const std::string& text) : _t(text.c_str()), _l(text.size(){}
    const void* _t;
    size_t _l;
};

struct asPointer {
    explicit asPointer(const char* _p) : p(_p) {}
    const char* p;
};

class Diagnostics
{
private:
    std::stringstream  m_stream;
    std::string        m_tag;
public:
    typedef std::ostream&  (*ManipFn)(std::ostream&);
    typedef std::ios_base& (*FlagsFn)(std::ios_base&);
    Diagnostics(const std::string& str) : m_tag(str) {}

    template<class T>  // int, double, strings, etc
    std::ostream& operator<<(const T& output)
    {
        m_stream << output;
        return m_stream;
    }

    std::ostream& operator<<(ManipFn manip) /// endl, flush, setw, setfill, etc.
    {
        manip(m_stream);

        if (manip == static_cast<ManipFn>(std::flush)
            || manip == static_cast<ManipFn>(std::endl ) ) {
            this->flush();
        }

        return m_stream;
    }

    Diagnostics& operator<<(FlagsFn manip) /// setiosflags, resetiosflags
    {
        manip(m_stream);
        return *this;
    }

    Diagnostics& operator()(std::string& e)
    {
        m_tag = e;
        return *this;
    }

    std::ostream& operator<<(struct asPointer ptr)
    {
        m_stream << "0x" << std::hex << std::setw(8) << std::setfill('0') << reinterpret_cast<const unsigned long long*>(ptr.p) << std::dec;
        return m_stream;
    }

    std::ostream& operator<<(struct asDigest dgst)
    {
        m_stream << std::string("Test Digest");
        return m_stream;
    }

    void flush()
    {
        /*
         MAKE CALL TO OS LOG HERE
        */
        m_stream.str( std::string() );
        m_stream.clear();
    }
};

预期用途如下:

Diagnostics("TAG") << "Message" << "MoreMessages" << std::endl

我可以创建一个记录器的实例,设置标签,并在到达 std::ostream& operator<<(const T& output) 上设置的断点后,我可以看到第一个字符串被送入流中。但是我很挣扎,因为似乎没有其他事情发生,后续字符串永远不会调用相同的方法,并且 flush() 永远不会被调用,所以我无法读取整个流。

我觉得我在这里遗漏了一些东西,或者我误解了 API。任何帮助实现我正在寻找的东西都将不胜感激。

问题在于 Diagnostics("TAG") << "Message" return 是对内部 m_streamostream& 引用,因此后续 ... << "MoreMessages" << std::endl 将直接转到该流,绕过你所有 class 的逻辑。

要正确链接您的 operator<<,他们都需要 return Diagnostics& 而不是 ostream&,将 return m_stream; 替换为 return *this; (您的 operator<<(FlagsFn)operator() 已经这样做了),例如:

template<class T>  // int, double, strings, etc
Diagnostics& operator<<(const T& output)
{
    m_stream << output;
    return *this;
}

Diagnostics& operator<<(ManipFn manip) /// endl, flush, setw, setfill, etc.
{
    manip(m_stream);

    if (manip == static_cast<ManipFn>(std::flush)
        || manip == static_cast<ManipFn>(std::endl ) ) {
        this->flush();
    }

    return *this;
}

Diagnostics& operator<<(FlagsFn manip) /// setiosflags, resetiosflags
{
    manip(m_stream);
    return *this;
}

Diagnostics& operator()(std::string& e)
{
    m_tag = e;
    return *this;
}

Diagnostics& operator<<(struct asPointer ptr)
{
    m_stream << "0x" << std::hex << std::setw(8) << std::setfill('0') << reinterpret_cast<const unsigned long long*>(ptr.p) << std::dec;
    return *this;
}

Diagnostics& operator<<(struct asDigest dgst)
{
    m_stream << "Test Digest";
    return *this;
}