簡體   English   中英

多態記錄器(虛擬模板函數?)

[英]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功能來同時使用ostreamqDebug() 而且我不想自己重新實現所有重載( ostream的長列表, qDebug甚至更長!)。

我想實現它,無論如何(lambda函數與auto ?)...任何建議歡迎(我可能在這里做錯了什么?)。

謝謝 :)

顯然不可能有模板化的虛函數,但你可以使用類型擦除來“擦除”具體類型,因此你不再需要模板了。

基本上,您創建了一個接口ILoggableValue ,它知道如何使用QDebugstd::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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM