How does QDebug() << stuff; add a newline au

2019-02-04 12:00发布

I'm trying to implement my own QDebug() style debug-output stream, this is basically what I have so far:

struct debug
{
#if defined(DEBUG)
    template<typename T>
    std::ostream& operator<<(T const& a) const
    {
        std::cout << a;
        return std::cout;
    }
#else
    template<typename T>
    debug const& operator<<(T const&) const
    {
        return *this;
    }

    /* must handle manipulators (endl) separately:
     * manipulators are functions that take a stream& as argument and return a
     * stream&
     */
    debug const& operator<<(std::ostream& (*manip)(std::ostream&)) const
    {
        // do nothing with the manipulator
        return *this;
    }
#endif
};

Typical usage:

debug() << "stuff" << "more stuff" << std::endl;

But I'd like not to have to add std::endl;

My question is basically, how can I tell when the return type of operator<< isn't going to be used by another operator<< (and so append endl)?

The only way I can think of to achieve anything like this would be to create a list of things to print with associated with each temporary object created by debug(), then to print everything, along with trailing newline (and I could do clever things like inserting spaces) in ~debug(), but obviously this is not ideal since I don't have a guarantee that the temporary object is going to be destroyed until the end of the scope (or do I?).

标签: c++ qt stream
4条回答
祖国的老花朵
2楼-- · 2019-02-04 12:14

When you write that this is the typical usage:

debug() << "stuff" << "more stuff" << std::endl;

are you definitely planning to construct a debug object each time you use it? If so, you should be able to get the behavior you want by having the debug destructor add the newline:

~debug()
{
    *this << std::endl;

    ... the rest of your destructor ...
}

That does mean you cannot do something like this:

// this won't output "line1" and "line2" on separate lines
debug d;
d << "line1";
d << "line2";
查看更多
【Aperson】
3楼-- · 2019-02-04 12:23

Qt uses a method similar to @Evan. See a version of qdebug.h for the implementation details, but they stream everything to an underlying text stream, and then flush the stream and an end-line on destruction of the temporary QDebug object returned by qDebug().

查看更多
Deceive 欺骗
4楼-- · 2019-02-04 12:37

Something like this will do:

struct debug {
    debug() {
    }

    ~debug() {
        std::cerr << m_SS.str() << std::endl;
    }

public:
    // accepts just about anything
    template<class T>
    debug &operator<<(const T &x) {
        m_SS << x;
        return *this;
    }
private:
    std::ostringstream m_SS;
};

Which should let you do things like this:

debug() << "hello world";

I've used a pattern like this combined with a lock to provide a stream like logging system which can guarantee that log entries are written atomically.

NOTE: untested code, but should work :-)

查看更多
神经病院院长
5楼-- · 2019-02-04 12:39

The stream insertion (<<) and extraction (>>) are supposed to be non-members.

My question is basically, how can I tell when the return type of operator<< isn't going to be used by another operator<< (and so append endl)?

You cannot. Create a member function to specially append this or append an endl once those chained calls are done with. Document your class well so that the clients know how to use it. That's your best bet.

查看更多
登录 后发表回答