代码之家  ›  专栏  ›  技术社区  ›  Amaterastis

基类接受子类和内部子类的模板参数

  •  0
  • Amaterastis  · 技术社区  · 5 月前

    我正在创建一个库,我希望用户能够像这样实例化它:

    int main (int, char**)
    {
        Child_Type1<int> c1 = Child_Type1<int>();
        Child_Type2<int> c2 = Child_Type2<int>();
        // ...
    }
    

    基类由三个模板参数定义,用作所有派生类的接口。类型T表示数据类型,类型U表示派生类本身,类型W表示U的内部类。

    template <class T, class U, class W>
    class Base
    {
    public:
        virtual void test(void) = 0;
    };
    

    其中一个派生类是:

    template <class T>
    class Child_Type1
    {
        class Inner;
    
    public:
        Inner* var;
    
        void test(void) override
        {
            // some code here
        }
    };
    

    嵌套类Inner在所有同名但元素不同的Child_TypeX中定义,例如:

    template <class T>
    class Child_Type1::Inner
    {
        T some_variable;
    };
    
    template <class T>
    class Child_Type2::Inner
    {
        T other_variable
    };
    
    // etc.
    

    当我尝试创建继承时,例如:

    template <class T>
    class Child_Type1 : public Base<T, Child_Type1<T>, Child_Type1<T>::Inner>
    

    我遇到了这个问题,因为Child_Type1::Inner还不存在。由于我不能在继承之前转发声明它,我想知道是否有人知道如何破解它。

    2 回复  |  直到 5 月前
        1
  •  1
  •   Jarod42    5 月前

    您可以声明/定义 Inner 外部:

    template <typename T>
    struct Inner;
    
    template <class T> class Child_Type1;
    template <class T> class Child_Type2;
    
    template <typename T>
    struct Inner<Child_Type1<T>>
    {
        T some_variable;
    };
    template <typename T>
    struct Inner<Child_Type2<T>>
    {
        T other_variable;
    };
    

    然后

    template <class T>
    class Child_Type1 : public Base<T, Child_Type1<T>, Inner<Child_Type1<T>>>
    {
    public:
        Inner<Child_Type1<T>>* var;
    
        void test() override
        {
            // some code here
        }
    };
    
        2
  •  1
  •   edrezen    5 月前

    你的设计看起来像 CRTP 自从 Child_Type1 继承由以下参数化的基类 儿童_类型1 本身,但不完全采用这种模式的原则,即只应将派生类传递给基类,而不应传递其他东西(如 T Child_Type1<T>::Inner 在您的示例中)。

    如果你完全遵循CRTP,你应该能够写:

    template <class T>
    class Child_Type1 : public Base<Child_Type1<T>> {};
    

    然后尝试恢复 Base 你需要的类型,即。 T 儿童_类型1<T>:内部

    请注意,您可以恢复 T Child_Type1<T> 有一个小助手(另见 this :

    template <typename T> 
    struct get_T;
    
    template <template <typename> class X,typename T>
    struct get_T<X<T>> { using type = T; };
    

    按照@Jarod42的答案并使用这个技巧,你可以得到这样的结果:

    
    ////////////////////////////////////////////////////////////////////////////////
    // see https://stackoverflow.com/questions/78048504/how-to-write-a-template-specialization-of-a-type-trait-that-works-on-a-class-tem
    template <typename T> 
    struct get_T;
    
    template <template <typename> class X,typename T>
    struct get_T<X<T>> { using type = T; };
    
    ////////////////////////////////////////////////////////////////////////////////
    template <typename T>
    struct Inner;
    
    ////////////////////////////////////////////////////////////////////////////////
    template <class DERIVED>
    class Base
    {
    public:
    
        using U = typename get_T<DERIVED>::type;
        using W = Inner<DERIVED>;
    
        virtual void test(void) = 0;
    };
    
    ////////////////////////////////////////////////////////////////////////////////
    template <class T>
    class Child_Type1 : public Base<Child_Type1<T>>
    {
    public:
    
        Base<Child_Type1<T>>::W * var;
    
        void test(void) override { var->some_variable; }
    };
    
    template <typename T>  struct Inner<Child_Type1<T>>  {  T some_variable;  };
    
    ////////////////////////////////////////////////////////////////////////////////
    int main()
    {
        Child_Type1<int> c1 = Child_Type1<int>();
    }