繁体   English   中英

CRTP(奇怪的重复模板模式)使用通用基础模板类而不是派生类

[英]CRTP (Curiously Recurring Template Pattern) using a generic base template class instead of the derived class

我最近一直在研究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文件中看到它的声明),只是它存在。

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

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

我不能过分评论大局,因为我不知道你想做什么。 我不太相信CRTP甚至适合你。 CRTP对某些事情很有用,但它并不是我转向的第一个工具。 实际上,现在我想起来了:我很少使用它。 在大多数情况下,如果我要使用基于模板的多态性,我可以直接拿着“孩子”并完全跳过基础,在很多情况下我觉得基地不足以买我。

我建议您在将来的SO问题中包含任何编译器错误。 祝好运!

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM