c++ - CRTP (Curiously Recurring Template Pattern) 使用通用基模板类而不是派生类

标签 c++ templates crtp

我最近一直在研究 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 类时,我不断收到编译错误(可能是因为我没有完全意识到的命名空间问题)。

任何建议或这种设计是否有效和有效?

最佳答案

我不太确定这里的设计目标是什么,但是关于不完整类型的规则以同样的方式适用,无论你是否在谈论模板,你只需要考虑模板在哪里被实例化。

在您的情况下,您试图避免在 SomeFile.cpp 中包含 AsArgument.h。但是,您使用 AsArgument 类实例化 Example 类模板。这意味着当您编译 SomeFile.cpp 时,该翻译单元对 AsArgument 类一无所知(因为它在 .h 文件中看不到它的声明),只知道它存在。

但是,如您所料,如果您只知道一个类存在,您将无法对它做很多事情。你甚至不能按值(value)持有它,因为你不知道它的大小。您不能使用它的任何界面。在您的示例中,编译器无法知道 AsArgument::DoThat 甚至存在(它不一定需要知道它做了什么,可以留给链接器)。请记住,Example 是在 SomeFile.cpp 中实例化的,因此编译器需要知道 DoThat 存在的位置。

所以你需要 AsArgument.h。对于普通类,您可以将声明放在 .h 文件中,并将定义(实现)放在 .cpp 文件中。但是 AsArgument 是一个模板类,所以一般情况下你不能那样做。如果您在预先知道的有限数量的类上进行模板化,并且愿意在所有这些类上明确地进行模板化,那么您只能对模板执行此操作。

我不能对大局发表太多评论,因为我不知道你想做什么。我不确定 CRTP 是否适合您。 CRTP 在某些方面很有用,但它并不是我真正使用的第一个工具。其实现在想想:我很少用。在大多数情况下,如果我要使用基于模板的多态性,我可以直接持有“ child ”并完全跳过基础,在很多情况下我觉得基础对我来说不够。

我建议在以后的 SO 问题中包括您遇到的任何编译器错误。祝你好运!

关于c++ - CRTP (Curiously Recurring Template Pattern) 使用通用基模板类而不是派生类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31151795/

相关文章:

c++ - 嵌套开关替代

c# - C# 中的 unsigned char 使用哪种数据类型?

javascript - 如何显示所有模板名称的列表?

c++ - 类模板实例化错误: type not declared in this scope

c++ - 使用 CRTP 分离平台特定代码

c++ - 在二维数组的矩形区域内快速找到最大值的方法

C++11模板别名作为模板模板参数导致不同的类型?

c++ - CRTP 自动注册工厂(静态初始化顺序失败)

c++ - 调用父构造函数时如何避免模板参数上的样板

C++:std::copy 失败,访问冲突读取位置错误