【问题标题】:How do I implement inheritance in a partial class template specialisation?如何在部分类模板专业化中实现继承?
【发布时间】:2018-03-17 14:32:28
【问题描述】:

我想我只是缺少一些小东西。我想将模板类的构造函数专门用于其中 T = 具有任何参数的模板类的实现。对不起,如果我的词汇有点不对劲。 基本上,我需要允许锯齿状的二维数组,所以我可能有一个ArEl<ArEl<int>>,我想预初始化所有数组长度。

using namespace std;

template <typename T>
class ArEl {
 public:
  ArEl(size_t size = 0)
      : rSize(size), rArray(rSize ? new T[rSize]() : nullptr) {}
  ArEl(const ArEl& other);
  virtual ~ArEl() { delete[] rArray; }
  void swap(ArEl& first, ArEl& second);
  void redim(size_t size);

 private:
  std::size_t rSize;
  T* rArray;
};

template <typename T, typename T1>
class ArEl<ArEl<T>> : public ArEl<T1>{
  ArEl(size_t size = 0);
};

编辑:

我收到此错误:

error: template parameters not deducible in partial specialization:
 class ArEl<ArEl<T>> : public ArEl<T1>{

【问题讨论】:

    标签: c++ class templates inheritance constructor


    【解决方案1】:

    您以错误的方式专业化您的对象。

    template&lt;typename T, typename T1&gt; 意味着需要提供两种数据类型,但很明显,您的模板特化唯一需要的是底层数组的数据类型。如果期望ArEl&lt;ArEl&lt;T&gt;&gt; 是专业化的,那么它不应该超过这个:

    template<typename T>
    class ArEl<ArEl<T>> {
        /*Blah Blah Blah*/
    };
    

    不需要继承,也不需要第二种数据类型。

    不过,我还要补充一点:一开始就没有任何必要进行这种专业化。如果您根本不编写专业化,则以下代码仍应按原样工作:

    ArEl<ArEl<int>> dim2Array(50);
    //I'm assuming ArEl will have a member size() function
    for(size_t index = 0; index < dim2Array.size(); index++) {
        //I'm assuming ArEl will have an operator[] overload
        dim2Array[index].redim(30);
    }
    //dim2Array is now 50 int arrays, each of size 30.
    

    我假设您想要的功能类似于以下内容,这确实需要模板专业化,就像我在上面发布的那样:

    ArEl<ArEl<int>> dim2Array(50, 30);
    //dim2Array is now 50 int arrays, each of size 30.
    

    但如果我是你,我会不理会ArEl 的实现,而是投资编写一个处理这种语法的Matrix&lt;T&gt; 类(或者可能是Matrix&lt;T, N&gt;,用于N 维)来处理这种语法(顺便说一句,您可以使用ArEl&lt;T&gt; 作为构建块来构建它),特别是因为我认为您并不致力于为ArEl&lt;ArEl&lt;ArEl&lt;int&gt;&gt;&gt; 或更深层次编写专业化(是的,您尝试这样做的方式,每个级别都需要自己的专业化)。

    【讨论】:

      【解决方案2】:

      特化整个类意味着用特化提供的成员替换所有成员。你不想这样。

      一种选择是在基类中提供所有需要特化的成员:BaseForA&lt;T&gt; 将是特化的,A&lt;T&gt; 将从它派生。

      另一种是使用标签调度,这里有一个示例,说明如何根据类型参数使用它来执行不同的操作。

      #include <iostream>
      #include <type_traits>
      
      template<typename T>
      struct tag {};
      
      template<typename T>
      struct A
      {
      private:
          template<typename U>
          A(std::size_t s, tag<A<U>>)
          {
              std::cout << "special constructor " << s << "\n";
          }
      
          A(std::size_t s, ...)
          {
              std::cout << "general constructor " << s << "\n";
          }
      public:
          A(std::size_t s = 0) :
              A(s, tag<T>())
          {
      
          }
      };
      
      int main() 
      {
          A<int> a;
          A<A<int>> b;
          A<A<long>> c;
          A<long> d;
      }
      

      Live on Coliru

      【讨论】:

        【解决方案3】:

        如果我理解正确,您希望专用版本继承通用版本,然后在其上添加一些内容。这里的问题是你有一个专门的ArEl&lt;ArEl&lt;T&gt;&gt;,你不能请求它的通用版本。

        解决办法是把通用版和专用版做成不同的类型。

        template<typename T, bool D=true>
        class ArEl { ...
        
        template<typename T>
        class ArEl<ArEl<T>>: 
            public ArEl<ArEl<T>, false> { ...
        

        但现在的问题是ArEl&lt;T, true&gt; 和ArEl&lt;T, false&gt; 是不相关且不兼容的!

        解决方案是为它们引入一个通用的基类。

        template<typename T>
        class ArElBase {
             ... all functionality of ArEl
        };
        
        template<typename T, bool D=true>
        class ArEl : public ArElBase<T> { 
           using ArElBase<T>::ArElBase;
           // nothing more
        }; 
        

        然后是专业化,不变。

        现在您可以使用 ArElBase 通过指针或引用传递您的对象,但使用 ArEl 来声明对象本身。

        【讨论】:

          猜你喜欢
          • 2017-01-05
          • 1970-01-01
          • 1970-01-01
          • 2015-08-21
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-12-17
          • 1970-01-01
          相关资源
          最近更新 更多