有沒有羨慕過python自帶的logging的易用性?這裏簡單地完成了一個較爲高效的模板化分級logger.
先理一下思路:
1.希望有一個根據字符串索引的單例集合
2.希望有一個可以分級的日誌管理
3.不要寫得太長
先來設計一下分級管理的標籤
/* Logger級別 */
namespace LoggerFlag {
struct logger_flag {};
struct critical_logger_flag : public logger_flag {};
struct error_logger_flag : public critical_logger_flag{};
struct debug_logger_flag : public error_logger_flag {};
struct warning_logger_flag : public debug_logger_flag {};
struct info_logger_flag : public warning_logger_flag {};
}
這個分級機制允許分級匹配,不過我們可以用type_traits,這樣效率更高。
namespace LoggerFlag {
template<typename m_flag> struct type_traitor;
template<typename m_flag>
struct type_traitor {
typedef std::true_type enable_info;
typedef std::true_type enable_warning;
typedef std::true_type enable_debug;
typedef std::true_type enable_error;
typedef std::true_type enable_critical;
};
template<>
struct type_traitor<critical_logger_flag> {
typedef logger_flag _ww;
typedef std::false_type enable_info;
typedef std::false_type enable_warning;
typedef std::false_type enable_debug;
typedef std::false_type enable_error;
typedef std::true_type enable_critical;
};
...
}
接下來是Logger的單例
/* Logger單例 */
class Logger
{
static Logger m_logger_instance;
protected:
typedef QDebug OutStream;
public:
static Logger *get_logger(const std::string &logger_name);
static OutStream criticals();
static OutStream errors();
static OutStream debugs();
static OutStream warnings();
static OutStream infos();
OutStream critical();
OutStream error();
OutStream debug();
OutStream warning();
OutStream info();
public:
protected:
Logger();
virtual ~Logger();
private:
template<typename out_flag=LoggerFlag::logger_flag>
Logger(out_flag);
};
如果我們直接在如critical()
裏返回一個qDebug,或者qNoDebug,用m_logger_instance作爲單例載體,那麼單例模式算是設計完了。
但是如何去設計static Logger *get_logger(const std::string &logger_name);
呢?
結合我們之前的分級方法,我們可能要先設計一個真正工作的Logger指針。
/* Logger指針 */
template <typename output_flag>
class LoggerHelper: public LoggerManagable
{
protected:
typedef QDebug OutStream;
public:
LoggerHelper();
~LoggerHelper();
OutStream _critical();
OutStream _error();
OutStream _debug();
OutStream _warning();
OutStream _info();
};
然後拿map<>(或unordered_map)保存每一個std::string對應的單例。
但是這裏LoggerHandler並不能寫在map<>的聲明上,所以我們還要加一個非泛型的基類。
/* Logger指針 */
class LoggerManagable
{
protected:
typedef QDebug OutStream; // <-把OutStream提升到這裏
public:
LoggerManagable();
virtual ~LoggerManagable() = 0;
virtual OutStream _critical() = 0;
virtual OutStream _error() = 0;
virtual OutStream _debug() = 0;
virtual OutStream _warning() = 0;
virtual OutStream _info() = 0;
};
然後用一個內存管理器的單例做一個tricky的編程
/* Logger單例管理器 */
class LoggerManager{
friend class Logger;
static std::map<std::string, Logger*> m_logger_instances;
static LoggerManager logger_destructor;
public:
LoggerManager();
~LoggerManager();
};
爲什麼上面是Logger*
?,我在Logger裏保存了LoggerManagable
的指針,這樣也是合情合理的。Logger
裏新添加的內容在下面:
/* Logger單例 */
class Logger
{
friend class LoggerManager;
private:
LoggerManagable *handler;
};
來看一下第一組實例代碼,單例的內存管理器是怎麼實現的?回顧以前的某一個blog,我們用那個思想做了一個威力加強版。
LoggerManager::LoggerManager()
{
m_logger_instances.clear();
}
LoggerManager::~LoggerManager()
{
for (auto &logger_instance: m_logger_instances) {
if (logger_instance.second != nullptr) {
#ifdef DEBUG
qDebug() << "logger" << QString::fromStdString(logger_instance.first) << "is destructed";
#endif
delete logger_instance.second;
logger_instance.second = nullptr;
}
}
}
用戶是沒有權限delete單例的,因此這裏map中的每一個指針都對應一個單例,放心釋放吧。
接下來是設計真正的handler.以critical
爲例:
/* 申請假的stream(Not True Type) */
template<typename request_bool_type>
inline LoggerManagable::OutStream LoggerManagable::request_stream() {
static QString idle_buffer;
static QDebug idle_dbg(&idle_buffer);
idle_buffer.clear();
return idle_dbg;
}
/* 申請真的stream(偏特化True Type) */
template<>
inline LoggerManagable::OutStream LoggerManagable::request_stream<std::true_type>() {
return qDebug();
}
/* 根據type_traits裏記錄的值選擇對應的stream */
template<typename out_flag>
LoggerManagable::OutStream LoggerHelper<out_flag>::_critical()
{
return request_stream<typename LoggerFlag::type_traitor<out_flag>::enable_critical::type>();
}
Logger::OutStream Logger::criticals()
{
return Logger::m_logger_instance.handler->_critical();
}
Logger::OutStream Logger::critical()
{
return this->handler->_critical();
}
這裏criticals
是單例的靜態方法。
其他的複製粘貼替換即可。
我們還差什麼?
好像還差分級。
一開始我的設計是這樣的。
/* Logger單例 */
class Logger
{
public:
template<typename out_flag>
bool set_mode();
template<typename out_flag>
static bool set_modes();
};
但是頭文件和實現的cpp文件分離了,會報未實例化偏函數的warning,忍不了。乾脆還是迴歸平常吧。
好在這裏 logger_flag都是一字節的,也沒有哪個程序會瘋狂更改mode,好像也不會浪費到哪裏去。
修改一下
/* Logger單例 */
class Logger
{
public:
bool set_mode(LoggerFlag::logger_flag);
bool set_mode(LoggerFlag::critical_logger_flag);
bool set_mode(LoggerFlag::error_logger_flag);
bool set_mode(LoggerFlag::debug_logger_flag);
bool set_mode(LoggerFlag::warning_logger_flag);
bool set_mode(LoggerFlag::info_logger_flag);
static bool set_modes(LoggerFlag::logger_flag);
static bool set_modes(LoggerFlag::critical_logger_flag);
static bool set_modes(LoggerFlag::error_logger_flag);
static bool set_modes(LoggerFlag::debug_logger_flag);
static bool set_modes(LoggerFlag::warning_logger_flag);
static bool set_modes(LoggerFlag::info_logger_flag);
};
下面是實現:
bool Logger::set_mode(LoggerFlag::logger_flag)
{
if (this->handler != nullptr) {
delete this->handler;
this->handler = nullptr;
}
this->handler = new LoggerHelper<LoggerFlag::logger_flag>;
return this->handler != nullptr;
}
bool Logger::set_modes(LoggerFlag::logger_flag)
{
if (m_logger_instance.handler != nullptr) {
delete m_logger_instance.handler;
m_logger_instance.handler = nullptr;
}
m_logger_instance.handler = new LoggerHelper<LoggerFlag::logger_flag>;
return m_logger_instance.handler != nullptr;
}
當然最重要的函數之一get_logger也有一些需要注意的地方,上代碼:
Logger *Logger::get_logger(const std::string &logger_name)
{
static std::mutex alloc_mutex;
if (!LoggerManager::m_logger_instances.count(logger_name)) {
alloc_mutex.lock();
if (!LoggerManager::m_logger_instances.count(logger_name)) {
LoggerManager::m_logger_instances[logger_name] = new Logger();
}
alloc_mutex.unlock();
}
return LoggerManager::m_logger_instances[logger_name];
}
這樣一個簡單的logger就完成了,雖然比較簡短,一些坑還是需要仔細琢磨才能做出來的…熟能生巧吧。
效果
qDebug() << Logger::set_modes(LoggerFlag::debug_logger_flag());
Logger::infos() << "w";
Logger::warnings() << "ww";
Logger::debugs() << "www";
Logger::errors() << "wwww";
Logger::criticals() << "wwwww";
qDebug() << Logger::set_modes(LoggerFlag::logger_flag());
Logger::infos() << "w";
Logger::warnings() << "ww";
Logger::debugs() << "www";
Logger::errors() << "wwww";
Logger::criticals() << "wwwww";
this->init_client();
auto dex = Logger::get_logger("main");
dex->info() << "...";
dex->warning() << "...";
dex->debug() << "...";
dex->error() << "...";
dex->critical() << "...";
dex->set_mode(LoggerFlag::debug_logger_flag());
qDebug() << "------------";
dex->info() << "...";
dex->warning() << "...";
dex->debug() << "...";
dex->error() << "...";
dex->critical() << "...";
auto dey = Logger::get_logger("main");
qDebug() << "------------";
dey->info() << "...";
dey->warning() << "...";
dey->debug() << "...";
dey->error() << "...";
dey->critical() << "...";
Logger::get_logger("a")->info() << "ww";
Logger::get_logger("b")->info() << "ww";
Logger::get_logger("c")->info() << "ww";
true
www
wwww
wwwww
true
w
ww
www
wwww
wwwww
...
...
...
...
...
------------
...
...
...
------------
...
...
...
ww
ww
ww
logger "a" is destructed
logger "b" is destructed
logger "c" is destructed
logger "main" is destructed
貼一下完整代碼
#ifndef LOGGGGER_H
#define LOGGGGER_H
#include <QString>
#include <iostream>
#include <string>
#include <map>
#include <mutex>
#include <type_traits>
#include <QDebug>
/* Logger級別 */
namespace LoggerFlag {
struct logger_flag {};
struct critical_logger_flag : public logger_flag {};
struct error_logger_flag : public critical_logger_flag{};
struct debug_logger_flag : public error_logger_flag {};
struct warning_logger_flag : public debug_logger_flag {};
struct info_logger_flag : public warning_logger_flag {};
template<typename m_flag> struct type_traitor;
}
/* Logger指針 */
class LoggerManagable
{
protected:
typedef QDebug OutStream;
public:
LoggerManagable();
virtual ~LoggerManagable() = 0;
virtual OutStream _critical() = 0;
virtual OutStream _error() = 0;
virtual OutStream _debug() = 0;
virtual OutStream _warning() = 0;
virtual OutStream _info() = 0;
template<typename request_bool_type>
inline LoggerManagable::OutStream request_stream();
};
/* Logger單例 */
class Logger
{
static Logger m_logger_instance;
friend class LoggerManager;
protected:
typedef QDebug OutStream;
public:
static Logger *get_logger(const std::string &logger_name);
static OutStream criticals();
static OutStream errors();
static OutStream debugs();
static OutStream warnings();
static void infos(const char *msg, ...);
static OutStream infos();
bool set_mode(LoggerFlag::logger_flag);
bool set_mode(LoggerFlag::critical_logger_flag);
bool set_mode(LoggerFlag::error_logger_flag);
bool set_mode(LoggerFlag::debug_logger_flag);
bool set_mode(LoggerFlag::warning_logger_flag);
bool set_mode(LoggerFlag::info_logger_flag);
static bool set_modes(LoggerFlag::logger_flag);
static bool set_modes(LoggerFlag::critical_logger_flag);
static bool set_modes(LoggerFlag::error_logger_flag);
static bool set_modes(LoggerFlag::debug_logger_flag);
static bool set_modes(LoggerFlag::warning_logger_flag);
static bool set_modes(LoggerFlag::info_logger_flag);
OutStream critical();
OutStream error();
OutStream debug();
OutStream warning();
OutStream info();
public:
protected:
Logger();
virtual ~Logger();
private:
template<typename out_flag=LoggerFlag::logger_flag>
Logger(out_flag);
LoggerManagable *handler;
};
/* Logger單例管理器 */
class LoggerManager{
friend class Logger;
static std::map<std::string, Logger*> m_logger_instances;
static LoggerManager logger_destructor;
public:
LoggerManager();
~LoggerManager();
};
/* Logger指針 */
template <typename output_flag>
class LoggerHelper: public LoggerManagable
{
public:
LoggerHelper();
~LoggerHelper();
OutStream _critical();
OutStream _error();
OutStream _debug();
OutStream _warning();
OutStream _info();
};
#endif // LOGGGGER_H
#include "Logger.h"
#include <QDebug>
#include <QMessageLogger>
/*********************************** Singletons ***********************************/
LoggerManager LoggerManager::logger_destructor;
Logger Logger::m_logger_instance;
std::map<std::string, Logger*> LoggerManager::m_logger_instances;
/*********************************** LoggerFlag ***********************************/
namespace LoggerFlag {
template<typename m_flag>
struct type_traitor {
typedef std::true_type enable_info;
typedef std::true_type enable_warning;
typedef std::true_type enable_debug;
typedef std::true_type enable_error;
typedef std::true_type enable_critical;
};
template<>
struct type_traitor<critical_logger_flag> {
typedef logger_flag _ww;
typedef std::false_type enable_info;
typedef std::false_type enable_warning;
typedef std::false_type enable_debug;
typedef std::false_type enable_error;
typedef std::true_type enable_critical;
};
template<>
struct type_traitor<error_logger_flag> {
typedef logger_flag _ww;
typedef std::false_type enable_info;
typedef std::false_type enable_warning;
typedef std::false_type enable_debug;
typedef std::true_type enable_error;
typedef std::true_type enable_critical;
};
template<>
struct type_traitor<debug_logger_flag> {
typedef logger_flag _ww;
typedef std::false_type enable_info;
typedef std::false_type enable_warning;
typedef std::true_type enable_debug;
typedef std::true_type enable_error;
typedef std::true_type enable_critical;
};
template<>
struct type_traitor<warning_logger_flag> {
typedef logger_flag _ww;
typedef std::false_type enable_info;
typedef std::true_type enable_warning;
typedef std::true_type enable_debug;
typedef std::true_type enable_error;
typedef std::true_type enable_critical;
};
template<>
struct type_traitor<info_logger_flag> {
typedef logger_flag _ww;
typedef std::false_type enable_info;
typedef std::true_type enable_warning;
typedef std::true_type enable_debug;
typedef std::true_type enable_error;
typedef std::true_type enable_critical;
};
}
/************************************* Logger *************************************/
Logger::Logger()
{
this->handler = new LoggerHelper<LoggerFlag::logger_flag>;
}
Logger::~Logger()
{
if (handler != nullptr) {
delete handler;
}
}
Logger *Logger::get_logger(const std::string &logger_name)
{
static std::mutex alloc_mutex;
if (!LoggerManager::m_logger_instances.count(logger_name)) {
alloc_mutex.lock();
if (!LoggerManager::m_logger_instances.count(logger_name)) {
LoggerManager::m_logger_instances[logger_name] = new Logger();
}
alloc_mutex.unlock();
}
return LoggerManager::m_logger_instances[logger_name];
}
/********************************* static methods *********************************/
Logger::OutStream Logger::criticals()
{
return Logger::m_logger_instance.handler->_critical();
}
Logger::OutStream Logger::errors()
{
return Logger::m_logger_instance.handler->_error();
}
Logger::OutStream Logger::debugs()
{
return Logger::m_logger_instance.handler->_debug();
}
Logger::OutStream Logger::warnings()
{
return Logger::m_logger_instance.handler->_warning();
}
Logger::OutStream Logger::infos()
{
return Logger::m_logger_instance.handler->_info();
}
/******************************** instance methods ********************************/
Logger::OutStream Logger::critical()
{
return this->handler->_critical();
}
Logger::OutStream Logger::error()
{
return this->handler->_error();
}
Logger::OutStream Logger::debug()
{
return this->handler->_debug();
}
Logger::OutStream Logger::warning()
{
return this->handler->_warning();
}
Logger::OutStream Logger::info()
{
return this->handler->_info();
}
/******************************** aborted methods ********************************/
//template<typename out_flag>
//bool Logger::set_mode()
//{
// if (this->handler != nullptr) {
// delete this->handler;
// this->handler = nullptr;
// }
// this->handler = new LoggerHelper<out_flag>;
// return this->handler != nullptr;
//}
//template<>
//bool Logger::set_mode<LoggerFlag::critical_logger_flag>()
//{
// if (this->handler != nullptr) {
// delete this->handler;
// this->handler = nullptr;
// }
// this->handler = new LoggerHelper<LoggerFlag::critical_logger_flag>;
// return this->handler != nullptr;
//}
//template<>
//bool Logger::set_mode<LoggerFlag::error_logger_flag>()
//{
// if (this->handler != nullptr) {
// delete this->handler;
// this->handler = nullptr;
// }
// this->handler = new LoggerHelper<LoggerFlag::error_logger_flag>;
// return this->handler != nullptr;
//}
//template<>
//bool Logger::set_mode<LoggerFlag::debug_logger_flag>()
//{
// if (this->handler != nullptr) {
// delete this->handler;
// this->handler = nullptr;
// }
// this->handler = new LoggerHelper<LoggerFlag::debug_logger_flag>;
// return this->handler != nullptr;
//}
//template<>
//bool Logger::set_mode<LoggerFlag::warning_logger_flag>()
//{
// if (this->handler != nullptr) {
// delete this->handler;
// this->handler = nullptr;
// }
// this->handler = new LoggerHelper<LoggerFlag::warning_logger_flag>;
// return this->handler != nullptr;
//}
//template<>
//bool Logger::set_mode<LoggerFlag::info_logger_flag>()
//{
// if (this->handler != nullptr) {
// delete this->handler;
// this->handler = nullptr;
// }
// this->handler = new LoggerHelper<LoggerFlag::info_logger_flag>;
// return this->handler != nullptr;
//}
//template<>
//bool Logger::set_modes<LoggerFlag::logger_flag>()
//{
// if (m_logger_instance.handler != nullptr) {
// delete m_logger_instance.handler;
// m_logger_instance.handler = nullptr;
// }
// m_logger_instance.handler = new LoggerHelper<LoggerFlag::logger_flag>;
// return m_logger_instance.handler != nullptr;
//}
//template<>
//bool Logger::set_modes<LoggerFlag::critical_logger_flag>()
//{
// if (m_logger_instance.handler != nullptr) {
// delete m_logger_instance.handler;
// m_logger_instance.handler = nullptr;
// }
// m_logger_instance.handler = new LoggerHelper<LoggerFlag::critical_logger_flag>;
// return m_logger_instance.handler != nullptr;
//}
//template<>
//bool Logger::set_modes<LoggerFlag::error_logger_flag>()
//{
// if (m_logger_instance.handler != nullptr) {
// delete m_logger_instance.handler;
// m_logger_instance.handler = nullptr;
// }
// m_logger_instance.handler = new LoggerHelper<LoggerFlag::error_logger_flag>;
// return m_logger_instance.handler != nullptr;
//}
//template<>
//bool Logger::set_modes<LoggerFlag::debug_logger_flag>()
//{
// if (m_logger_instance.handler != nullptr) {
// delete m_logger_instance.handler;
// m_logger_instance.handler = nullptr;
// }
// m_logger_instance.handler = new LoggerHelper<LoggerFlag::debug_logger_flag>;
// return m_logger_instance.handler != nullptr;
//}
//template<>
//bool Logger::set_modes<LoggerFlag::warning_logger_flag>()
//{
// if (m_logger_instance.handler != nullptr) {
// delete m_logger_instance.handler;
// m_logger_instance.handler = nullptr;
// }
// m_logger_instance.handler = new LoggerHelper<LoggerFlag::warning_logger_flag>;
// return m_logger_instance.handler != nullptr;
//}
//template<>
//bool Logger::set_modes<LoggerFlag::info_logger_flag>()
//{
// if (m_logger_instance.handler != nullptr) {
// delete m_logger_instance.handler;
// m_logger_instance.handler = nullptr;
// }
// m_logger_instance.handler = new LoggerHelper<LoggerFlag::info_logger_flag>;
// return m_logger_instance.handler != nullptr;
//}
//template<typename out_flag>
//bool Logger::set_modes()
//{
// qDebug() << "this flag is invalid";
// return false;
//}
/******************************** set_mode methods ********************************/
bool Logger::set_mode(LoggerFlag::critical_logger_flag)
{
if (this->handler != nullptr) {
delete this->handler;
this->handler = nullptr;
}
this->handler = new LoggerHelper<LoggerFlag::critical_logger_flag>;
return this->handler != nullptr;
}
bool Logger::set_mode(LoggerFlag::error_logger_flag)
{
if (this->handler != nullptr) {
delete this->handler;
this->handler = nullptr;
}
this->handler = new LoggerHelper<LoggerFlag::error_logger_flag>;
return this->handler != nullptr;
}
bool Logger::set_mode(LoggerFlag::debug_logger_flag)
{
if (this->handler != nullptr) {
delete this->handler;
this->handler = nullptr;
}
this->handler = new LoggerHelper<LoggerFlag::debug_logger_flag>;
return this->handler != nullptr;
}
bool Logger::set_mode(LoggerFlag::warning_logger_flag)
{
if (this->handler != nullptr) {
delete this->handler;
this->handler = nullptr;
}
this->handler = new LoggerHelper<LoggerFlag::warning_logger_flag>;
return this->handler != nullptr;
}
bool Logger::set_mode(LoggerFlag::info_logger_flag)
{
if (this->handler != nullptr) {
delete this->handler;
this->handler = nullptr;
}
this->handler = new LoggerHelper<LoggerFlag::info_logger_flag>;
return this->handler != nullptr;
}
bool Logger::set_mode(LoggerFlag::logger_flag)
{
if (this->handler != nullptr) {
delete this->handler;
this->handler = nullptr;
}
this->handler = new LoggerHelper<LoggerFlag::logger_flag>;
return this->handler != nullptr;
}
/******************************** setmodes methods ********************************/
bool Logger::set_modes(LoggerFlag::logger_flag)
{
if (m_logger_instance.handler != nullptr) {
delete m_logger_instance.handler;
m_logger_instance.handler = nullptr;
}
m_logger_instance.handler = new LoggerHelper<LoggerFlag::logger_flag>;
return m_logger_instance.handler != nullptr;
}
bool Logger::set_modes(LoggerFlag::info_logger_flag)
{
if (m_logger_instance.handler != nullptr) {
delete m_logger_instance.handler;
m_logger_instance.handler = nullptr;
}
m_logger_instance.handler = new LoggerHelper<LoggerFlag::info_logger_flag>;
return m_logger_instance.handler != nullptr;
}
bool Logger::set_modes(LoggerFlag::warning_logger_flag)
{
if (m_logger_instance.handler != nullptr) {
delete m_logger_instance.handler;
m_logger_instance.handler = nullptr;
}
m_logger_instance.handler = new LoggerHelper<LoggerFlag::warning_logger_flag>;
return m_logger_instance.handler != nullptr;
}
bool Logger::set_modes(LoggerFlag::debug_logger_flag)
{
if (m_logger_instance.handler != nullptr) {
delete m_logger_instance.handler;
m_logger_instance.handler = nullptr;
}
m_logger_instance.handler = new LoggerHelper<LoggerFlag::debug_logger_flag>;
return m_logger_instance.handler != nullptr;
}
bool Logger::set_modes(LoggerFlag::error_logger_flag)
{
if (m_logger_instance.handler != nullptr) {
delete m_logger_instance.handler;
m_logger_instance.handler = nullptr;
}
m_logger_instance.handler = new LoggerHelper<LoggerFlag::error_logger_flag>;
return m_logger_instance.handler != nullptr;
}
bool Logger::set_modes(LoggerFlag::critical_logger_flag)
{
if (m_logger_instance.handler != nullptr) {
delete m_logger_instance.handler;
m_logger_instance.handler = nullptr;
}
m_logger_instance.handler = new LoggerHelper<LoggerFlag::critical_logger_flag>;
return m_logger_instance.handler != nullptr;
}
/******************************** Logger Manager *********************************/
LoggerManager::LoggerManager()
{
m_logger_instances.clear();
}
LoggerManager::~LoggerManager()
{
for (auto &logger_instance: m_logger_instances) {
if (logger_instance.second != nullptr) {
#ifdef DEBUG
qDebug() << "logger" << QString::fromStdString(logger_instance.first) << "is destructed";
#endif
delete logger_instance.second;
logger_instance.second = nullptr;
}
}
}
/******************************** request stream ********************************/
template<typename request_bool_type>
inline LoggerManagable::OutStream LoggerManagable::request_stream() {
static QString idle_buffer;
static QDebug idle_dbg(&idle_buffer);
idle_buffer.clear();
return idle_dbg;
}
template<>
inline LoggerManagable::OutStream LoggerManagable::request_stream<std::true_type>() {
return qDebug();
}
/****************************** select output or not ******************************/
template<typename out_flag>
LoggerManagable::OutStream LoggerHelper<out_flag>::_critical()
{
return request_stream<typename LoggerFlag::type_traitor<out_flag>::enable_critical::type>();
}
template<typename out_flag>
LoggerManagable::OutStream LoggerHelper<out_flag>::_error()
{
return request_stream<typename LoggerFlag::type_traitor<out_flag>::enable_error::type>();
}
template<typename out_flag>
LoggerManagable::OutStream LoggerHelper<out_flag>::_debug()
{
return request_stream<typename LoggerFlag::type_traitor<out_flag>::enable_debug::type>();
}
template<typename out_flag>
LoggerManagable::OutStream LoggerHelper<out_flag>::_warning()
{
return request_stream<typename LoggerFlag::type_traitor<out_flag>::enable_warning::type>();
}
template<typename out_flag>
LoggerManagable::OutStream LoggerHelper<out_flag>::_info()
{
return request_stream<typename LoggerFlag::type_traitor<out_flag>::enable_info::type>();
}
/******************************** void constructor ********************************/
template<typename output_flag>
LoggerHelper<output_flag>::LoggerHelper() {}
template<typename output_flag>
LoggerHelper<output_flag>::~LoggerHelper() {}
LoggerManagable::LoggerManagable() {}
LoggerManagable::~LoggerManagable() {}
看起來有點長,但都是複製粘貼…
補充:
有一個小bug= =,沒想到運行了十幾次以後隨機出現了這個錯誤。
LoggerManager LoggerManager::logger_destructor
和std::map<> m_logger_instances
之間有依賴關係(你也不能假定全局變量的初始化有先後順序,這和編譯器有關,是未定義行爲),不能同時聲明爲全局變量。解決辦法是將m_logger_instances
設爲指針,並在LoggerManager
中完成對m_logger_instances
的操作。