我正在用c ++写一个日志类。这个班是一个单身人士。我想以这样的方式添加日志:
Log::GetInstance() << "Error: " << err_code << ", in class foo";
好的,在Log对象中,我希望在最后一个参数出现时保存整行(“,在本例中的类foo中)。
如何检测最后一个&lt;&lt;争论? &LT;&LT; a&lt;&lt; b&lt;&lt; is_this_last&lt;&lt; maybe_this_is&lt;&lt; or_not。
我不使用任何结束标记。
答案 0 :(得分:17)
您可以通过不使用单例来解决此问题。如果你做了这样的函数:
Log log()
{
return Log();
}
您可以像以前一样添加日志:
log() << "Error: " << err_code << ", in class foo";
不同之处在于Log
对象的析构函数在此行之后被调用。所以现在你有办法检测最后一个参数的处理时间。
答案 1 :(得分:9)
我希望你的Log::GetInstance
返回代理对象而不是日志对象本身。代理对象将保存写入其中的数据,然后在其析构函数中,它实际上将累积的数据写入日志。
答案 2 :(得分:4)
在运算符&lt;&lt;之后,使Log返回另一个对象。
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;
}
答案 3 :(得分:4)
我认为Jerry和Martin给出了最好的建议,但为了完整起见,我想到的第一件事是std::endl
。
如果您通过自定义Log
课程在iostream
系统中实施了streambuf
,则可以在结尾处添加<< endl
或<< flush
线。既然你问,我想你没有。
但你可以模仿endl
的工作方式。添加操纵器处理程序
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; }
或添加专用的operator<<
struct Flog {} flog;
Log &operator<< ( Log &l, Flog )
{ l->flush(); return l; }
答案 4 :(得分:1)
不要让操作员太聪明。在有意义的情况下,您应该重载运算符。在这里你不应该。 这看起来很奇怪。
你应该有一个如下所示的静态方法:
Log::Message( message_here );
采用std :: string。然后,客户可以清楚地知道如何组装错误字符串。
答案 5 :(得分:0)
没有好办法做你想做的事。 C和C ++根本不是面向行的语言。没有更大的单位,如“代码行”或任何东西,链接的调用也不会以任何方式组合。
在C ++中,表达式“a&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&quot;
t1 = a;
t2 = t1.operator<<(b);
t3 = t2.operator<<(c);
t4 = t3.operator<<(d);
这就是为什么C ++ ostreams使用endl作为明确的行尾标记;否则就没有办法做到这一点。
答案 6 :(得分:0)
这是基于@martin-york 的回答的解决方案。稍微修改以在结构中使用成员运算符。
#include<sstream>
#include<iostream>
struct log_t{
void publish(const std::string &s){
std::cout << s << std::endl;
}
};
struct record_t{
struct record_appender_t
{
record_appender_t(record_t& record_) : record(record_) {}
record_t& record;
~record_appender_t()
{
// Do stuff when this object is eventually destroyed
// at the end of the expression.
record.flush();
}
template<typename T>
record_appender_t& operator<<(T const& data)
{
record.stream() << data;
// Return a reference to the input so we can chain.
// The object is thus not destroyed until the end of the stream.
return *this;
}
};
std::ostringstream message;
log_t log;
void flush(){
log.publish(message.str());
}
std::ostringstream& stream() {
return message;
}
template<typename T>
record_appender_t operator<<(T const& data)
{
// Put stuff in log.
message << data;
// now return the object to detect the end of the statement.
return record_appender_t(*this);
}
};
#define LOG \
record_t()
int main(){
LOG << 1 << 2 << "a";
}