我最近一直在研究CRTP,并提出了使用CRTP创建通用基本模板类的想法。
// Example.h
namespace A {
template <class TClass, typename T>
class Example {
public:
Example(T &someStruct) : m_someStruct_(someStruct)
{
}
~Example()
{
DoThis();
}
public:
void DoThis()
{
static_cast<TClass*>(this)->DoThat(m_someStruct_);
}
private:
T m_someStruct_;
};
}
// AsArgument.h
namespace A {
class AsArgument : public Example <AsArgument, SomeStruct> {
friend class Example <AsArgument, SomeStruct>;
private:
void DoThat(SomeStruct &someFun)
{
// Do something to someFun object.
// yehey(someFun);
printf("I want to do that! \n");
}
};
}
我的目标是使用基类对象来访问派生类的函数,同时通过仅包含基类的头文件来分离基类和派生的实现,并将派生类声明为模板参数
我知道我可以用不完整类型做什么的基础知识,但我似乎无法找到有关模板的信息。
转发声明类TDerived参数而不是包含头文件是否有效?
// SomeFile.cpp
#include "Example.h"
class A::AsArgument; // Forward declare this instead of including the AsArgument.h header file
namespace B {
void SomeClass::DoSomething()
{
SomeStruct fun;
Example <AsArgument, SomeStruct> example(fun);
}
}
我不确定这是否是创建通用基本模板类的好设计,但是我在建立基类之后的目标是从中轻松创建派生类并在编译时定义基类实现。 它实际上是某种RAII和CRTP的组合。
我实际上可以通过将“AsArgument.h”文件包含在“Example.h”中来实现这一点,但基本和实现之间的分离将丢失。当我尝试转发声明AsArgument类时,我不断收到编译错误(可能是因为我不完全了解命名空间问题)。
任何建议或这种设计是否有效且有效?
答案 0 :(得分:1)
我不确定这里的设计目标是什么,但是关于不完整类型的规则是否以同样的方式应用,无论您是否在谈论模板,您只需要考虑模板的位置实例化。
在您的情况下,您试图避免在SomeFile.cpp中包含AsArgument.h。但是,您使用AsArgument类实例化Example类模板。这意味着当你编译SomeFile.cpp时,那个翻译单元对AsArgument类一无所知(因为它没有在.h文件中看到它的声明),只有它存在。
然而,正如您所料,如果您只知道它存在,您就无法对课程做很多事情。你甚至不能按价值持有它,因为你不知道它的大小。您无法使用其任何界面。在您的示例中,编译器无法知道AsArgument :: DoThat是否存在(它不一定需要知道它的作用,可以留给链接器)。请记住,Example正在SomeFile.cpp中实例化,因此编译器需要知道DoThat存在。
所以你需要AsArgument.h。使用普通类,您可以将声明放在.h文件中,并将定义(实现)放在.cpp文件中。但AsArgument是一个模板类,所以你不能这样做。如果您对有限数量的类进行模板化(事先已知)并且愿意在所有类上明确模板,则只能对模板执行此操作。
我无法对大局进行过多评论,因为我不知道你要做什么。我不太相信CRTP甚至适合你。 CRTP对某些事情很有用,但它并不是我转向的第一个工具。实际上,现在我想起来了:我很少使用它。在大多数情况下,如果我要使用基于模板的多态性,我可以只保留&#34;孩子&#34;直接和完全跳过基地,在很多情况下我不觉得基地给我足够的购买。
我建议您在将来的SO问题中包含任何编译器错误。祝你好运!