多态记录器(虚拟模板化函数?
Polymorphic logger (virtual templated functions?)
上下文
我有一个被几个软件使用的库。有些是基本的命令行,有些具有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<<
的强大功能用于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;
};
这是一个活生生的例子。
- C++setiosflags函数操纵器-未确定的缩进
- 将函数包装器转换为 std::function
- C++函数包装器来捕获某些信号
- 创建 Spdlog 异步文件记录器时遇到困难
- 如何将自定义记录器与websocketpp一起使用?
- 在C++中隐藏键盘记录器的控制台窗口
- 考虑引用和常量的可变参数函数包装器
- 为什么Qt Creator的应用程序输出不能从spdlog记录器打印
- 麻烦得到提升::记录器编译
- 如何使用可变模板编写通用函数包装器
- 我正在尝试用 c++ 制作一个日志记录框架,但信息没有传递给记录器的子组件,我做错了什么?
- 其他成员函数的通用"成员函数"包装器?
- 多态记录器(虚拟模板化函数?
- 设置提升记录器的线程名称
- Boost Log的琐碎记录器"lazy evaluation"是如何工作的?
- boost::log 设置"Channel"通道记录器中的属性
- 当程序从该函数调谐器时,指向在函数中声明和定义的某些 C 字符串的指针不再有效.为什么?
- 将文件、函数、行添加到全局升压记录器
- 重载<<函数(记录器类)的C++链接
- 使用qInstallMessageHandler的记录器类找不到指向函数的指针