我正在用 C++ 编写一个日志类。这个类是一个单例。我想以这种方式添加日志:
Log::GetInstance() << "Error: " << err_code << ", in class foo";
好的,在 Log 对象中,我想在最后一个参数出现时保存整行(在本例中为“,在类 foo 中”)。
如何检测最后一个 << 参数?<< a << b << is_this_last << 也许_this_is << or_not。
我不使用任何结束标签。
我正在用 C++ 编写一个日志类。这个类是一个单例。我想以这种方式添加日志:
Log::GetInstance() << "Error: " << err_code << ", in class foo";
好的,在 Log 对象中,我想在最后一个参数出现时保存整行(在本例中为“,在类 foo 中”)。
如何检测最后一个 << 参数?<< a << b << is_this_last << 也许_this_is << or_not。
我不使用任何结束标签。
您可以通过不使用单例来解决此问题。如果你做一个这样的函数:
Log log()
{
return Log();
}
您可以使用几乎与之前相同的方式添加日志:
log() << "Error: " << err_code << ", in class foo";
不同之处在于Log
对象的析构函数在这一行之后被调用。所以现在你有一种方法可以检测最后一个参数何时被处理。
我会让你Log::GetInstance
返回一个代理对象而不是日志对象本身。代理对象将保存写入它的数据,然后在其析构函数中,它实际上会将累积的数据写入日志。
您使 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;
}
我认为 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; }
不要对你的操作员太聪明。在有意义的情况下,您应该重载运算符。在这里你不应该。这看起来很奇怪。
您应该只有一个如下所示的静态方法:
Log::Message( message_here );
它需要一个 std::string。然后,客户会为弄清楚如何组装错误字符串而头疼。
没有什么好方法可以做你想做的事。C 和 C++ 根本不是面向行的语言。没有像“代码行”或任何更大的单元,也没有以任何方式组合的链式调用。
在 C++ 中,表达式“a << b << c << d” 完全等同于对 operator<< 的三个单独调用,如下所示:
t1 = a;
t2 = t1.operator<<(b);
t3 = t2.operator<<(c);
t4 = t3.operator<<(d);
这就是 C++ ostream 使用 endl 作为显式行尾标记的原因。否则就没有像样的方法。
这是基于@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";
}