您可以創建一個可變參數模板函數(比如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日誌級別?我無法想象析構函數會做什麼。如果你願意的話,擁有兩種解決方案都是非常好的。 –
「日誌級別」意味着您可以爲日誌消息分配不同的優先級,然後在運行時(例如響應配置文件)決定顯示或不顯示。例如,您可能會記錄對調試有用的信息,但通常不會記錄該信息,除非有人遇到問題並決定將其打開。 –