您可以创建一个可变参数模板函数(比如log_it
),其采用AN_ENUM
加项记录的变量数,锁定mutex
一次,然后流一切a_stringstream
。例如:
#include <mutex>
#include <sstream>
#include <vector>
class save_stream
{
std::ostream& os_;
char fill_;
std::ios::fmtflags flags_;
std::streamsize precision_;
public:
~save_stream()
{
os_.fill(fill_);
os_.flags(flags_);
os_.precision(precision_);
}
save_stream(const save_stream&) = delete;
save_stream& operator=(const save_stream&) = delete;
explicit save_stream(std::ostream& os)
: os_(os)
, fill_(os.fill())
, flags_(os.flags())
, precision_(os.precision())
{}
};
struct log
{
std::mutex mut;
std::stringstream a_stringstream;
};
std::vector<log> logs(10);
enum : std::size_t {AN_ENUM};
void
log_one(std::size_t)
{
}
template <class Arg0, class ...Args>
void
log_one(std::size_t log, Arg0 const& arg0, Args const& ...args)
{
logs[log].a_stringstream << arg0;
log_one(log, args...);
}
template <class ...Args>
void
log_it(std::size_t log, Args const& ...args)
{
std::lock_guard<std::mutex> lock(logs[log].mut);
save_stream s{logs[log].a_stringstream};
logs[log].a_stringstream << "log " << log << " says : ";
log_one(log, args...);
logs[log].a_stringstream << '\n';
}
这不是一个很大数量的代码。 log_it
取一个整数常量,用它来索引到logs
来锁定互斥锁,吐出前缀字符串,然后调用log_one
带有常量日志索引和可变参数数量注销。
log_one
然后简单地记录第一个参数,然后在包的其余部分递归调用log_one
。
它可以像这样使用:
log_it(AN_ENUM, std::fixed, std::setprecision(3), "i = ", 4.5);
log_it(AN_ENUM, "j = ", 4.5);
导致logs[0].a_stringstream
控股:
log 0 says : i = 4.500
log 0 says : j = 4.5
我敢肯定,语法可以巧妙的东西更漂亮,但得到的基本想法跨越:传递可变数量的参数,锁定在调用堆栈的顶部,然后逐个处理每个参数。
“日志级别”可能只是log_it
的另一个参数。
一个典型的设置是使用'logs [AN_ENUM] << a << b << c;',其中第一个'<<'返回一个包含带'<<'的析构函数完成的所有stringstream的对象工作。但是,霍华德建议使用函数调用语法的一个优点是,如果此消息低于当前级别,则可以实现日志级别,然后不会在运行时浪费时间。 –
@ M.M日志级别?我无法想象析构函数会做什么。如果你愿意的话,拥有两种解决方案都是非常好的。 –
“日志级别”意味着您可以为日志消息分配不同的优先级,然后在运行时(例如响应配置文件)决定显示或不显示。例如,您可能会记录对调试有用的信息,但通常不会记录该信息,除非有人遇到问题并决定将其打开。 –