operator << - how to detect last argument

不羁的心 提交于 2019-12-07 06:30:42

问题


I'm writting a log class in c++. This class is an singleton. I want to add logs in such a way:

Log::GetInstance() << "Error: " << err_code << ", in class foo";

Ok, and inside a Log object, I want to save this whole line at the time when the last argument comes (", in class foo" in this example).

How to detect the last one << argument? << a << b << is_this_last << maybe_this_is << or_not.

I dont to use any end tags.


回答1:


You can solve this problem by not using a singleton. If you make a function like this:

Log log()
{
    return Log();
}

You can add a log almost the same way you did before:

log() << "Error: " << err_code << ", in class foo";

The difference is that the destructor of the Log object gets called after this line. So now you have a way to detect when the last argument has been processed.




回答2:


I would have your Log::GetInstance return a proxy object instead of the log object itself. The proxy object will save the data that's written to it, and then in its destructor, it'll actually write the accumulated data to the log.




回答3:


You make Log return a different object after the operator << .

template<typename T>
LogFindT operator<<(Log aLog, T const& data)
{
    // Put stuff in log.
    log.putStuffInLog(data);

    // now return the object to detect the end of the statement.
    return LogFindT(aLog);
}


struct LogFindT
{
    LogFindT(Log& aLog) : TheLog(aLog) {}
    Log& TheLog;
    ~LogFindT()
    {
        // Do stuff when this object is eventually destroyed
        // at the end of the expression.
    }
};

template<typename T>
LogFindT& operator<<(LogFindT& aLog, T const& data)
{
     aLog.TheLog.putStuffInLog(data);

     // Return a reference to the input so we can chain.
     // The object is thus not destroyed until the end of the stream.
     return aLog;
}



回答4:


I think Jerry and Martin have given the best suggestion, but for the sake of completeness, the first thing I thought of was std::endl.

If you implemented Log within the iostream system by a custom streambuf class, then you can simply add << endl or << flush at the end of the line. Since you're asking, I suppose you didn't.

But you can mimic the way endl works. Either add a manipulator handler

Log &operator<< ( Log &l, Log & (*manip)( Log & ) )
    { return manip( l ); } // generically call any manipulator

Log &flog( Log &l ) // define a manipulator "flush log"
    { l->flush(); return l; }

or add a dedicated operator<<

struct Flog {} flog;

Log &operator<< ( Log &l, Flog )
    { l->flush(); return l; }



回答5:


Don't get too clever with your operators. You should overload operators when it makes sense to do so. Here you don't should not. That just looks weird.

You should just have a static method that looks like this:

Log::Message( message_here );

which takes a std::string. Then clients have the head-ache of figuring out how to assemble the error string.




回答6:


There's no good way to do what you want. C and C++ are simply not line-oriented languages. There is no larger unit like a "line of code" or anything, nor are chained calls combined in any way.

In C++ the expression "a << b << c << d" is exactly equivalent to three separate calls to operator<<, like this:

 t1 = a;
 t2 = t1.operator<<(b);
 t3 = t2.operator<<(c);
 t4 = t3.operator<<(d);

That's why C++ ostreams use endl as an explicit end-of-line marker; there's just no decent way to do it otherwise.



来源:https://stackoverflow.com/questions/3497181/operator-how-to-detect-last-argument

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!