CRTP(Curiously Recurring Template Pattern)使用通用基础模板 class 而不是派生的 class
CRTP (Curiously Recurring Template Pattern) using a generic base template class instead of the derived class
我最近一直在研究 CRTP,并想出了一个使用 CRTP 创建通用基础模板的想法class。
// 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");
}
};
}
我的目标是使用基础 class 对象访问派生的 class' 函数,同时通过仅包含基础 class 来分离基础和派生的实现]' 头文件并向前声明派生的 class 作为模板参数。
我知道我可以用不完整类型做什么的基础知识,但我似乎找不到有关模板的信息。
转发声明 class 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);
}
}
我不确定这是否是创建通用基础模板的好设计 class,但我在建立基础 class 后的目标是轻松创建派生的 classes从中取出并在编译时定义基础 class 实现。
它实际上是 RAII 和 CRTP 的某种组合。
我实际上可以通过将 "AsArgument.h" 文件包含在 "Example.h" 中来实现这一点,但是基础和实现之间的分离丢失了。当我尝试转发声明 AsArgument class 时,我不断收到编译错误(可能是因为我没有完全意识到的名称空间问题)。
任何建议或这种设计是否有效有效?
我不太确定这里的设计目标是什么,但是关于不完整类型的规则以同样的方式适用,无论你是否在谈论模板,你只需要考虑模板在哪里被实例化.
在你的例子中,你试图避免在 SomeFile.cpp 中包含 AsArgument.h。但是,您使用 AsArgument class 实例化示例 class 模板。这意味着当您编译 SomeFile.cpp 时,该翻译单元对 AsArgument class 一无所知(因为它在 .h 文件中看不到它的声明),只知道它存在。
但是,如您所料,如果您只知道 class 存在,您将无能为力。你甚至不能按价值持有它,因为你不知道它的大小。您不能使用它的任何界面。在您的示例中,编译器无法知道 AsArgument::DoThat 甚至存在(它不一定需要知道它的作用,可以留给链接器)。请记住,Example 是在 SomeFile.cpp 中实例化的,因此编译器需要知道 DoThat 存在的位置。
所以你需要AsArgument.h。对于正常的 class,您可以将声明放在 .h 文件中,并将定义(实现)放在 .cpp 文件中。但是 AsArgument 是一个模板class,所以一般情况下你不能那样做。如果您在预先知道的有限数量的 classes 上进行模板化,并且愿意在所有这些上明确地进行模板化,则只能对模板执行此操作。
我不能对大局发表太多评论,因为我不知道你想做什么。我不确定 CRTP 是否适合您。 CRTP 在某些方面很有用,但它并不是我真正使用的第一个工具。其实现在想想:我很少用。在大多数情况下,如果我要使用基于模板的多态性,我可以直接持有 "child" 并完全跳过基数,在很多情况下我觉得基数对我来说不够。
我建议在以后的 SO 问题中包括您遇到的任何编译器错误。祝你好运!
我最近一直在研究 CRTP,并想出了一个使用 CRTP 创建通用基础模板的想法class。
// 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");
}
};
}
我的目标是使用基础 class 对象访问派生的 class' 函数,同时通过仅包含基础 class 来分离基础和派生的实现]' 头文件并向前声明派生的 class 作为模板参数。
我知道我可以用不完整类型做什么的基础知识,但我似乎找不到有关模板的信息。
转发声明 class 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);
}
}
我不确定这是否是创建通用基础模板的好设计 class,但我在建立基础 class 后的目标是轻松创建派生的 classes从中取出并在编译时定义基础 class 实现。 它实际上是 RAII 和 CRTP 的某种组合。
我实际上可以通过将 "AsArgument.h" 文件包含在 "Example.h" 中来实现这一点,但是基础和实现之间的分离丢失了。当我尝试转发声明 AsArgument class 时,我不断收到编译错误(可能是因为我没有完全意识到的名称空间问题)。
任何建议或这种设计是否有效有效?
我不太确定这里的设计目标是什么,但是关于不完整类型的规则以同样的方式适用,无论你是否在谈论模板,你只需要考虑模板在哪里被实例化.
在你的例子中,你试图避免在 SomeFile.cpp 中包含 AsArgument.h。但是,您使用 AsArgument class 实例化示例 class 模板。这意味着当您编译 SomeFile.cpp 时,该翻译单元对 AsArgument class 一无所知(因为它在 .h 文件中看不到它的声明),只知道它存在。
但是,如您所料,如果您只知道 class 存在,您将无能为力。你甚至不能按价值持有它,因为你不知道它的大小。您不能使用它的任何界面。在您的示例中,编译器无法知道 AsArgument::DoThat 甚至存在(它不一定需要知道它的作用,可以留给链接器)。请记住,Example 是在 SomeFile.cpp 中实例化的,因此编译器需要知道 DoThat 存在的位置。
所以你需要AsArgument.h。对于正常的 class,您可以将声明放在 .h 文件中,并将定义(实现)放在 .cpp 文件中。但是 AsArgument 是一个模板class,所以一般情况下你不能那样做。如果您在预先知道的有限数量的 classes 上进行模板化,并且愿意在所有这些上明确地进行模板化,则只能对模板执行此操作。
我不能对大局发表太多评论,因为我不知道你想做什么。我不确定 CRTP 是否适合您。 CRTP 在某些方面很有用,但它并不是我真正使用的第一个工具。其实现在想想:我很少用。在大多数情况下,如果我要使用基于模板的多态性,我可以直接持有 "child" 并完全跳过基数,在很多情况下我觉得基数对我来说不够。
我建议在以后的 SO 问题中包括您遇到的任何编译器错误。祝你好运!