如何像 std C++ 流一样使用我的日志记录类?

问题描述 投票:0回答:6

我有一个工作记录器类,它将一些文本输出到 Richtextbox(Win32,C++)中。 问题是,我总是这样使用它:

stringstream ss;  
ss << someInt << someString;  
debugLogger.log(ss.str());

相反,像流一样使用它会更方便,如下所示:

debugLogger << someInt << someString;

有没有比将所有内容转发到内部 stringstream 实例更好的方法?如果这样做,我什么时候需要冲洗?

c++ logging stream
6个回答
36
投票

您需要为您的班级适当实施

operator <<
。一般模式如下所示:

template <typename T>
logger& operator <<(logger& log, T const& value) {
    log.your_stringstream << value;
    return log;
}

请注意,这涉及(非

const
)引用,因为该操作会修改您的记录器。另请注意,您需要返回
log
参数才能使链接正常工作:

log << 1 << 2 << endl;
// is the same as:
((log << 1) << 2) << endl;

如果最里面的操作没有返回当前的

log
实例,所有其他操作要么在编译时失败(错误的方法签名),要么在运行时被吞没。


16
投票

重载插入运算符<< is not the way to go. You will have to add overloads for all the endl or any other user defined functions.

方法是定义自己的streambuf,并将其绑定到流中。然后,您只需使用流即可。

以下是一些简单的例子:


4
投票

正如 Luc Hermitte 指出的那样,有一篇 “Logging In C++” 文章描述了解决此问题的非常巧妙的方法。简而言之,假设您有一个如下所示的函数:

void LogFunction(const std::string& str) { // write to socket, file, console, e.t.c std::cout << str << std::endl; }

可以编写一个包装器以在 std::cout 中使用它,就像这样:

#include <sstream> #include <functional> #define LOG(loggingFuntion) \ Log(loggingFuntion).GetStream() class Log { using LogFunctionType = std::function<void(const std::string&)>; public: explicit Log(LogFunctionType logFunction) : m_logFunction(std::move(logFunction)) { } std::ostringstream& GetStream() { return m_stringStream; } ~Log() { m_logFunction(m_stringStream.str()); } private: std::ostringstream m_stringStream; LogFunctionType m_logFunction; }; int main() { LOG(LogFunction) << "some string " << 5 << " smth"; }

(

在线演示)

此外,Stewart 提供了非常好的

解决方案


3
投票
一个同时解决冲洗问题的优雅解决方案如下:

#include <string> #include <memory> #include <sstream> #include <iostream> class Logger { using Stream = std::ostringstream; using Buffer_p = std::unique_ptr<Stream, std::function<void(Stream*)>>; public: void log(const std::string& cmd) { std::cout << "INFO: " << cmd << std::endl; } Buffer_p log() { return Buffer_p(new Stream, [&](Stream* st) { log(st->str()); }); } }; #define LOG(instance) *(instance.log()) int main() { Logger logger; LOG(logger) << "e.g. Log a number: " << 3; return 0; }
    

0
投票
聚会迟到了,但也可以将

std::ostringstream

 扩展到登录 destruct 的一个,然后将其用作“临时”(不要给它命名,所以它会立即破坏):

class StreamToLog : public std::ostringstream { int level = INFO; public: StreamToLog(int level); ~StreamToLog(); }; StreamToLog::StreamToLog(int level) : level(level) { } StreamToLog::~StreamToLog() { const std::string s = str(); // This 'cout' is simply for demo purposes. You can do anything else // like invoke a standard logger. std::cout << levelToString(level) << " " << s << std::endl; }
然后你可以在某处实现一些函数来检索该流:

StreamToLog Logger::log(int level) { return StreamToLog(level); }
然后记录如下:

Logger::log(DEBUG) << "Hello, I'll have " << 3 " beers.";
    

-1
投票
在 Logger 类中,覆盖

<< operator.

点击

这里了解如何实施 << operator.

您还可以避免代码中的日志语句 使用面向方面的编程。

© www.soinside.com 2019 - 2024. All rights reserved.