2

给定以下工作代码。

#include <iostream>

template<class Detail>
class AbstractLogger
{
public:
    static void log(const char* str) {
        Detail::log_detailled(str);
    }
};

class Logger : public AbstractLogger<Logger>
{
public:
    static void log_detailled(const char* str) {
        std::cerr << str << std::endl;
    }
};

int main(void)
{
    AbstractLogger<Logger>::log("main function running!");
    return 0;
}

现在,我想放入AbstractLogger一个库,让库用户定义自己的记录器,就像Logger这里的类一样。这有一个缺点:AbstractLogger<Logger>不能在库内部使用,因为库无法知道Logger.

笔记:

  • 请不要虚函数或问题为什么不。另外,我知道“静态虚拟”成员无效的类似问题。也许,CRTP 中有一个解决方法:)
  • C++11 会很有趣,但是,我需要“通常的”C++。
4

3 回答 3

2

如果您的意思是您希望有一个库在不知道确切的实例化类型的情况下使用它作为日志记录机制,我建议您不要这样做。

在满足您的其他要求(即没有虚函数)的同时这样做的唯一方法是将库中需要记录的所有函数/类型转换为采用该Logger类型的模板。最终结果是您的大部分界面都变成了模板(尽管您可能可以将大量实现转移到非模板代码中,但这会使您的生活变得比需要的困难得多,并且仍然会生成更大的二进制文件) .

如果您对虚函数的关注是性能,那么您应该重新考虑您的方法及其带来的问题。特别是,日志记录昂贵的。大多数日志库通过优化非日志案例来解决它(通过在未启用日志级别/组/...时避免调用记录器的宏),但仍然为实际写入保留动态调度。与写入控制台或文件的成本,甚至与生成将被记录的消息的成本相比,动态调度的成本可以忽略不计(我假设您不仅记录文字字符串)

于 2012-10-12T19:55:04.870 回答
1

通常的方法是针对一个概念进行编码,同时提供帮助程序,以便用户可以轻松地生成满足这些概念中的一个或多个的类型。例如,boost::iterator_facadeCRTP helper 之类的东西可以让用户更轻松地编写迭代器。然后,该迭代器可以在任何接受迭代器的地方使用——例如在std::vector. 请注意,该特定构造函数如何不知道用户定义的类型。

在您的情况下,AbstractLogger将是 CRTP 助手。缺少的部分是定义例如记录器的概念。因此,请注意需要记录器的所有内容要么需要作为模板实现,要么您需要一个类型擦除容器来保存任意记录器。

概念检查(如Boost提供的那些)对于这种编程很方便,因为它们允许用实际代码表示一个概念。

于 2012-10-12T20:00:53.163 回答
0

模板类不能“放入库中”,因为它们被编译器实例化为模板参数的特化。

不过,您可以将模板实现中使用的与参数无关的东西放入库中。

于 2012-10-12T19:55:48.603 回答