我有一个支持iostream
的自定义日志记录类 - 通过模板operator <<
语法
template< class T >
MyLoggingClass & operator <<(MyLoggingClass &, const T &) {
// do stuff
}
我还有一个专门版本的运算符,应该在日志消息完成时调用:
template< >
MyLoggingClass & operator <<(MyLoggingClass &, consts EndOfMessageType &){
// build the message and process it
}
EndOfMessageType
的定义如下:
class EndOfMessageType {};
const EndOfMessageType eom = EndOfMessageType( );
定义全局常量eom
,以便用户可以在日志消息的末尾使用std::endl
。我的问题是,这个解决方案是否有任何陷阱,或者是否有一些既定模式可以做到这一点?
提前致谢!
答案 0 :(得分:2)
std::endl
是一个函数,而不是一个对象,并且operator<<
被重载以接受指向函数的指针并返回对ostream
的引用。此重载只调用函数并传递*this
。
#include <iostream>
int main()
{
std::cout << "Let's end this line now";
std::endl(std::cout); //this is the result of cout << endl, or cout << &endl ;)
}
只是另一种选择。
顺便说一下,我认为没有必要专门化运算符:正常的重载也是如此,如果不是更好的话。
答案 1 :(得分:0)
我认为你的解决方案是可以接受的。如果您想以不同方式执行此操作,则可以创建一个类Message
,该类将用于代替您的MyLoggingClass
并提供自动终止。
{
Message m;
m << "Line: " << l; // or m << line(l)
m << "Message: foo"; // or m << message("foo");
log << m; // this would automatically format the message
}
答案 2 :(得分:0)
我做过this way,和其他人一样。有一个函数Error
/ Log
/ Warning
/ etc,看起来像这样
DiagnosticBuilder Error( ErrType type, string msg, int line );
这将返回一个临时构建器对象,其类基本上定义为
struct DiagnosticBuilder {
DiagnosticBuilder(std::string const& format)
:m_emit(true), m_format(format)
{ }
DiagnosticBuilder(DiagnosticBuilder const& other)
:m_emit(other.m_emit), m_format(other.m_format), m_args(other.m_args) {
other.m_emit = false;
}
~DiagnosticBuilder() {
if(m_emit) {
/* iterate over m_format, and print the next arg
everytime you hit '%' */
}
}
DiagnosticBuilder &operator<<(string const& s) {
m_args.push_back(s);
return *this;
}
DiagnosticBuilder &operator<<(int n) {
std::ostringstream oss; oss << n;
m_args.push_back(oss.str());
return *this;
}
// ...
private:
mutable bool m_emit;
std::string m_format;
std::vector<std::string> m_args;
};
因此,如果您在循环中构建日志消息,那么就这样
DiagnosticBuilder b(Error("The data is: %"));
/* do some loop */
b << result;
一旦自动调用构建器的析构函数,就会发出消息。大多数情况下你会匿名使用它
Error("Hello %, my name is %") << "dear" << "litb";