重载运算符<&书信电报;在C++;带前缀 我在C++中使用日志记录类,它有以下语法: Logger log("mylog.txt"); log << "a string" << " " << 1 << " " << 6.2 << "\n";
我想到了几个解决方案: 1.将每个输入保存在列表/流中,并使用额外功能打印并清除列表/流:重载运算符<&书信电报;在C++;带前缀 我在C++中使用日志记录类,它有以下语法: Logger log("mylog.txt"); log << "a string" << " " << 1 << " " << 6.2 << "\n";,c++,operator-overloading,C++,Operator Overloading,我想到了几个解决方案: 1.将每个输入保存在列表/流中,并使用额外功能打印并清除列表/流: Logger log("mylog.txt"); log << "a string" << " " << 1 << " " << 6.2 << "\n"; log.logd(); // <- this prints and then clears the internal stream/list. Logger日志(“mylo
Logger log("mylog.txt");
log << "a string" << " " << 1 << " " << 6.2 << "\n";
log.logd(); // <- this prints and then clears the internal stream/list.
Logger日志(“mylog.txt”);
log您需要为Logger引入一个额外的包装器类,它知道行是开始还是追加
class Appender
{
Appender(Logger& logger) : os_(os) { }
Appender& operator <<(const T& x) { os_ << x; return *this; }
};
class Logger
{
Appender operator <<(const T& x) { os_ << timestamp() << x; return Appender(os_); }
};
类追加器
{
Appender(记录器和记录器):os_z(os){}
Appender&operator实际代码将更加复杂,但请尝试实现以下逻辑
添加一个成员变量bool last char was newline,并在如下代码中使用它:
template<typename T>
Logger& operator<< (const T& data)
{
if (last_char_was_newline) {
*m_pOutStream << current_time_string();
last_char_was_newline = false;
}
*m_pOutStream << data;
if (last_char(data) == '\n') {
last_char_was_newline = true;
}
return *this;
}
模板
Logger&operator从std::stringbuf
派生一个类,比如说LoggerStringBuf
,并在其构造函数中给它一个对输出std::ofstream
的引用。重写虚拟std::stringbuf::sync()
方法,从基std::stringbuf::str()检索std::string
方法,并在将其写入std::ofstream
时为其加上时间戳前缀。这样,每当您的LoggerStringBuf
对象出于任何原因刷新到std::ofstream
时,无论是通过std::endl
或std::flush
显式刷新,还是通过其destru隐式刷新,都会生成一个新的时间戳克托尔
然后让您的Logger
类从std::ostream
派生,并用LoggerStringBuf
对象初始化它。然后您可以将输入值流式传输到Logger
中,它们将缓存在LoggerStringBuf
对象中,直到刷新到std::ofstream
。此时您可以预处理根据需要挂起时间戳
例如:
class LoggerStringBuf : public std::stringbuf
{
private:
std::ostream &m_OutStream;
protected:
virtual int sync()
{
int ret = std::stringbuf::sync();
std::string s = str();
str("");
// note sure if the string includes non-flushing
// line breaks. If needed, you can use std::getline()
// to break up the string into multiple lines and
// write a timestamp for each line...
//
m_OutStream << "[timestamp] " << s << std::endl;
return ret;
};
public:
LoggerStringBuf(std::ostream &OutStream)
: std::stringbuf(std::ios_base::out), m_OutStream(OutStream)
{
}
~LoggerStringBuf()
{
sync();
}
};
class Logger : public std::ostream
{
private:
std::ofstream m_OutStream;
LoggerStringBuf m_Buf;
public:
Logger(const std::string &sFile)
: std::ostream(0), m_OutStream(sFile, std::ios::app), m_Buf(m_OutStream)
{
init(&m_Buf);
}
template<typename T>
std::ostream& operator<< (const T& data)
{
return static_cast<std::ostream&>(*this) << data;
}
};
类LoggerStringBuf:public std::stringbuf
{
私人:
std::奥斯特雷姆和摩托扩流;
受保护的:
虚拟整数同步()
{
int ret=std::stringbuf::sync();
std::string s=str();
str(“”);
//请注意,如果管柱包括非冲洗管柱,请确保
//换行符。如果需要,可以使用std::getline()
//将字符串拆分为多行,然后
//为每行写一个时间戳。。。
//
m_超出了旁白,但重载的运算符不应该使用标志来指示最后一个字符输出是否为换行符。当您被调用并设置标志时,首先输出前缀。该标志应默认为true
,以便您也在输出的第一行之前打印前缀。根据我的经验,最好不要o将“行”概念与“日志条目”分开概念和时间戳项。@MOLBNILO对日志文件中的不同行具有不同的格式,这使得处理这些行的编写工具更加困难。@CONCONINTERIST我的建议不需要保存任何输出。它只需要一个变量,bool last\u char\u was\u newline;
返回Appender&Logger::operatorProxy类的ode>看起来是一个优雅的解决方案,但是请注意,OP希望在每一行上打印时间戳,因此调用Logger会复杂得多…您的代码基本上是无用的。您需要在le处处理std::string
、char
和std::endl
重载AST,提供了良好的类型演绎。我明白了,就像我说的,我试图展示一般逻辑,而不是确切的代码。我可以编写伪代码,但我决定用C++语法来显示它。是的,这个想法似乎不错,但是用一般的方式实现并不微不足道。我已经添加了一个关于如何用一般方式来做它的额外想法。使用std::stringstram
。这两行代码在LoggerStringBuf::sync()的实现中的作用是什么?std::string s=str();str(“”;
@dgellow on cppreference.com.sync()调用
将缓存数据写入目标输出。该代码从基类检索缓存数据,然后重置基类中的缓存,因此,如果以后再次调用sync()
,则不会记录相同的数据。
class Appender
{
Appender(Logger& logger) : os_(os) { }
Appender& operator <<(const T& x) { os_ << x; return *this; }
};
class Logger
{
Appender operator <<(const T& x) { os_ << timestamp() << x; return Appender(os_); }
};
template<typename T>
Logger& operator<< (const T& data)
{
if (last_char_was_newline) {
*m_pOutStream << current_time_string();
last_char_was_newline = false;
}
*m_pOutStream << data;
if (last_char(data) == '\n') {
last_char_was_newline = true;
}
return *this;
}
class LoggerStringBuf : public std::stringbuf
{
private:
std::ostream &m_OutStream;
protected:
virtual int sync()
{
int ret = std::stringbuf::sync();
std::string s = str();
str("");
// note sure if the string includes non-flushing
// line breaks. If needed, you can use std::getline()
// to break up the string into multiple lines and
// write a timestamp for each line...
//
m_OutStream << "[timestamp] " << s << std::endl;
return ret;
};
public:
LoggerStringBuf(std::ostream &OutStream)
: std::stringbuf(std::ios_base::out), m_OutStream(OutStream)
{
}
~LoggerStringBuf()
{
sync();
}
};
class Logger : public std::ostream
{
private:
std::ofstream m_OutStream;
LoggerStringBuf m_Buf;
public:
Logger(const std::string &sFile)
: std::ostream(0), m_OutStream(sFile, std::ios::app), m_Buf(m_OutStream)
{
init(&m_Buf);
}
template<typename T>
std::ostream& operator<< (const T& data)
{
return static_cast<std::ostream&>(*this) << data;
}
};