C++ 不知道派生类型的静态CRTP类?
给出以下工作代码C++ 不知道派生类型的静态CRTP类?,c++,templates,static,crtp,C++,Templates,Static,Crtp,给出以下工作代码 #include <iostream> template<class Detail> class AbstractLogger { public: static void log(const char* str) { Detail::log_detailled(str); } }; class Logger : public AbstractLogger<Logger> { public: stat
#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;
}
#包括
模板
类抽象记录器
{
公众:
静态无效日志(常量字符*str){
详细信息:日志详细信息(str);
}
};
类记录器:公共抽象记录器
{
公众:
静态无效日志(const char*str){
如果您的意思是希望有一个库使用它作为日志机制,而不知道确切的实例化类型,那么我建议不要使用它
在满足其他要求(即没有虚拟函数)的情况下,唯一的方法是将库中所有需要记录的函数/类型转换为采用记录器
类型的模板。最终结果是大部分界面都变成了模板(尽管您可能会将大量实现转移到非模板化代码,但这将使您的生活比需要的困难得多,而且它仍然会生成更大的二进制文件)
如果您对虚拟函数的关注点是性能,那么您应该重新考虑您的方法及其带来的问题。尤其是,日志成本很高。大多数日志库通过优化非日志情况来解决这一问题(通过宏来避免在未启用日志级别/组/…的情况下调用日志),但仍保留动态调度用于实际写入。与写入控制台或文件的成本相比,动态调度的成本可以忽略不计,甚至与生成将被记录的消息的成本相比(我假设您不仅记录文字字符串)模板类不能“放入库中”,因为它们被编译器实例化为模板参数的专门化
不过,您可以将模板实现中使用的与参数无关的内容放入库中。通常的方法是针对概念编写代码,同时提供帮助程序,以便用户可以轻松生成满足其中一个或多个概念的类型。例如,boost::iterator\u facade
之类的东西就是CRTP帮助程序at使用户更容易编写迭代器。然后,该迭代器可以在接受迭代器的任何位置使用——例如在std::vector
的范围构造函数中。请注意,该特定构造函数对用户定义的类型没有先见之明
在您的情况下,AbstractLogger
将是CRTP助手。缺少的部分是定义例如记录器概念。因此,请注意,需要记录器的所有内容都需要实现为模板,或者您需要一个类型擦除容器来容纳任意记录器
概念检查(如提供的检查)对于这种编程来说很方便,因为它们允许用实际代码表示概念。你说我想把AbstractLogger
放进一个库是什么意思。你是说你想在库中使用它而不知道实例化类型?还是想在库中包含某种生成的代码?还是就像CRT模式的严重设计缺陷和滥用一样…模板在代码中定义时被编译成具体的类表示形式。如果您定义了AbstractLogger
和AbstractLogger
,将编译两个版本。在库中,您必须事先定义可用的内容。谢谢您的回答。可以吗请简要介绍一下这样一个“类型擦除容器”是什么样子?@Johannes它将非常类似于std::function
,它是一个容器,用于任何可以用签名R(a…)
调用的内容。因此它将有一个构造函数模板容器(日志记录器日志)
获取任何符合记录器的内容,并且本身符合记录器概念——将实际操作委托给在构建时传递的记录器。概述了一些类型擦除技术。