[英]Polymorphic logger (virtual templated functions?)
CONTEXT
我有一個由幾個軟件使用的庫。 一些是基本命令行,一些是Qt UI。
我想在這個庫中實現一個獨特的日志類,所以每個軟件都可以使用它。 但是,如果我們處於Qt環境中,我想將qDebug()
函數與特定的QtMessageHandler
。 目標是能夠記錄此庫中的錯誤,並且日志將以不同方式打印,具體取決於庫是否在UI環境中使用(庫與Qt無依賴關系)。
我想要的是
在全球范圍內,我想要這樣的事情:
class Logger
{
public:
template <class T>
void log(const T& tolog) { handler.log(tolog); }
void setHandler(HANDLER???& h) { handler = h; }
const HANDLER???& getHandler() const { return handler; }
private:
HANDLER??? handler;
}
使用處理程序,對於命令行軟件,非常簡單,如:
class CLHandler
{
public:
template <class T>
void log(const T& tolog) { out << tolog << std::endl; }
private:
std::ostream out;
}
對於UI,我想使用qDebug()
所以我可以設置一個自定義QtMessageHandler
來在UI中打印錯誤,並將其記錄在一個文件中:
class UIHandler
{
public:
template <class T>
void log(const T& tolog) { qDebug() << tolog; }
}
問題
正如您所看到的,問題出在Logger
類中:處理程序將是什么類型?
由於虛擬模板功能,我無法真正創建接口:
class IHandler
{
public:
virtual ~IHandler() = default;
template <class T>
virtual void log(const T& tolog) = 0; // ERROR templated virtual function!
}
需要幫忙
我希望IHandler::tolog
函數是模板化的,因為我想使用operator<<
IHandler::tolog
功能來同時使用ostream
和qDebug()
。 而且我不想自己重新實現所有重載( ostream的長列表, qDebug甚至更長!)。
我想實現它,無論如何(lambda函數與auto
?)...任何建議歡迎(我可能在這里做錯了什么?)。
謝謝 :)
顯然不可能有模板化的虛函數,但你可以使用類型擦除來“擦除”具體類型,因此你不再需要模板了。
基本上,您創建了一個接口ILoggableValue
,它知道如何使用QDebug
和std::ostream
流記錄您的值,並使用模板為不同類型生成具體的實現:
class ILoggableValue {
public:
virtual ~ILoggableValue() = default;
virtual void log(QDebug &os) const = 0;
virtual void log(std::ostream &os) const = 0;
};
template <typename T>
class LoggableValue : public ILoggableValue {
public:
LoggableValue(const T &value) : value{value} {}
void log(QDebug &os) const override {
// implementation of log for QDebug goes here
os << value;
}
void log (std::ostream &os) const override {
// implementation of log for std::ostream goes here
os << value << std::endl;
}
private:
const T &value;
};
然后,按照建議的方式創建IHandler
,但現在可以使用ILoggableValue
擦除模板:
class IHandler {
public:
virtual ~IHandler() = default;
virtual void log(const ILoggableValue &tolog) const = 0;
};
class CLHandler : public IHandler {
public:
explicit CLHandler(std::ostream &out) : out{out} {}
void log(const ILoggableValue &tolog) const override {
tolog.log(out);
}
private:
std::ostream &out;
};
class UIHandler : public IHandler {
public:
void log(const ILoggableValue &tolog) const override {
tolog.log(qDebug());
}
};
最后,在Logger
使用IHandler
:
class Logger {
public:
Logger(std::unique_ptr<IHandler> h) : handler(std::move(h)) {}
template <class T>
void log(const T& tolog) { handler->log(LoggableValue<T>(tolog)); }
void setHandler(std::unique_ptr<IHandler> &h) { handler = std::move(h); }
const IHandler &getHandler() const { return *handler; }
private:
std::unique_ptr<IHandler> handler;
};
這是一個實例。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.