多个类的父级的部分专业化

问题描述

| 我想对模板类使用部分专业化,以便该模板类的所有子级都将使用该专业化。让我用一个例子解释一下:)
template < typename T,unsigned int rows,unsigned int cols>
class BaseMatrix {...};
此类将有指定矩阵结构的子级,例如稀疏,密集,对角线。
template < typename T,unsigned int cols>
class DiagonalMatrix : public BaseMatrix<T,rows,cols>{..}
然后这些类将再次具有指定存储的子代:堆栈数组,向量,列表,队列等。
template < typename T,unsigned int cols>
class StackDiagonalMatrix : public DiagonalMatrix<T,cols> {..}
然后是一个提供所有数学功能的Matrix类。该模板类实现operator +,operator-等。
   template <typename T,template<typename,unsigned,unsigned> class MatrixContainer,unsigned Rows,unsigned Cols>
    class matrix;
对于最后一堂课,我想写这样的专业化知识:
template <typename T,unsigned Cols>
class matrix<T,BaseMatrix,Rows,Cols> {};

template <typename T,DiagonalMatrix,Cols>  {};
但是,当我编写从DiagonalMatrix继承的StackDiagonalMatrix时,它没有找到DiagonalMatrix的专业化-实际上根本找不到专业化。
error: aggregate ‘matrix<int,StackDenseMatrix,3u,2u> matrix’ has incomplete type and cannot be defined
现在有解决此问题的方法吗?您可以为几个模板类的父类编写专门化的文字吗? 非常感谢! 涉及的完整资料:
    template <typename T,unsigned int cols>
    class BaseMatrix {
    protected:
        BaseMatrix(){};
        static const unsigned rowSize = rows;
        static const unsigned colSize = cols;
    };

    template <typename T,unsigned int cols>
    class DenseMatrix : public BaseMatrix<T,cols> {
    protected:
        DenseMatrix(){};

    };

    template <typename T,unsigned int cols>
    class StackDenseMatrix : public DenseMatrix<T,cols> {

    public:
        typedef T                                           value_type;

    private:
        value_type                                          grid[rows][cols];
        StackDenseMatrix();
    };

    template<typename value_type,unsigned int cols>
    StackDenseMatrix<value_type,cols>::StackDenseMatrix () {
        for (unsigned int i = 0; i < this->rowSize; i++) {
            for (unsigned int j = 0; j < this->colSize; j++) {
                grid[i][j] = 0;
            }
        }
    }

    template <typename T,unsigned Cols>
    class matrix;

    template <typename T,unsigned Cols>
    class matrix<T,Cols> {
         matrix(){};
};

int main () {
    matrix<int,3,2> matrix;
    return 0;
}
    

解决方法

        继承不适用于模板专业化。当您调用
matrix<int,StackDenseMatrix,3,2> matrix;
时,它将为
matrix
选择通用模板,因为第二个参数是
StackDenseMatrix
,而不是
BaseMatrix
。即使这些类通过继承而关联,也没有任何区别,它们不是完全相同的类型,因此编译器不会选择
matrix
的特殊化。 为了解决您的问题,在这种情况下,我认为继承不会为您带来任何好处。在通用编程中,更合适的工具是类型特征,策略和概念。在这种情况下,您应该能够应用一些类型特征来实现相似的目标。我喜欢使用的一个技巧是默认模板参数,该参数取决于先前的模板参数,然后进行部分专业化处理。举例如下:
enum MatrixStorage {
  DenseMatrix,SparseMatrix
};

enum MatrixStructure {
  GeneralMatrix,SquareMatrix,DiagonalMatrix  //,...
};

template <typename T,unsigned Rows,unsigned Cols>
class StackDenseMatrix {
  public: 
    typedef T value_type;
    static const MatrixStorage Storage = DenseMatrix;
    static const MatrixStructure Structure = GeneralMatrix;
  //..
};

//General template with default arguments:
template <typename T,template <typename,unsigned,unsigned> class MatrixContainer,unsigned Cols,MatrixStorage Storage = MatrixContainer<T,Rows,Cols>::Storage,MatrixStructure Structure = MatrixContainer<T,Cols>::Structure>
class matrix;

//Specialization with given arguments:
template <typename T,unsigned Cols>
class matrix<T,MatrixContainer,Cols,DenseMatrix,GeneralMatrix> {
  //implementation of matrix for when the container is dense and has general structure...
};

int main() {
  matrix<int,2> M; //no extra arguments,and the right specialization will be selected based on the traits of StackDenseMatrix.
  return 0;
};
我有自己的矩阵库,该矩阵库高度依赖于模板的上级编程和通用编程技术,与上述示例类似,可以为不同类型的矩阵结构和存储提供特殊的矩阵操作实现,并且这种方式非常有效。我曾经将继承用于不同的矩阵类型,但是现在我改用仅依赖于类型特征,概念,策略和Sfinae开关,这是一种更为实用的解决方案。     ,        要解决您的问题,可以使用基于策略的设计。您可以创建存储和形状的实例策略类。
class Diagonal  {
public:
    // the default storage facility of a Diagonal matrix
    typedef Stack default_storage;
};

template <typename T,typename Shape = DefaultShape,typename Storage = DefaultStorage,unsigned Row,unsigned Col>
class Matrix : public Storage,Shape {   // policy classes Storage and Shape
public:
    template <typename T1,typename Shape1,typename Storage1,unsigned Row1,unsigned Col1>
    friend Matrix<T1,Shape1,Storage1,Row1,Col1>& operator += (Matrix<T1,Col1> matrix1,Matrix<T,Shape,Storage,Row,Col> matrix2);

    template <typename T1,Diagonal,unsigned Col1>
    friend Matrix<T,Col>& operator + (Matrix<T,Col> matrix1,Col> matrix2);

// general template function
template <typename T,typename Shape,typename Storage,unsigned Col>
Matrix<T,Col> matrix2) {
    Matrix<T,Col>* result = new Matrix<T,Col>();
    for (unsigned i = 0; i < matrix1.getRowSize(); i++) {           // getRowSize is a member function of policy class Storage
        for (unsigned j = 0; j < matrix1.getRowSize(); j++) {
            (*result)(i,j) = matrix1.getValue(i,j) + matrix2.getValue(i,j);
        }
    }
    return *result;
}

// overloaded template function
template <typename T,Col>();
    for (unsigned i = 0; i < matrix1.getRowSize(); i++) {
        (*result)(i,i) = matrix1.getValue(i,i) + matrix2.getValue(i,i);
    }
    return *result;
}

// general template function
template <typename T,Col>& operator += (Matrix<T,Col> matrix2)  {
    Matrix<T,Col>(matrix1); // copy constructor
    for (unsigned i = 0; i < matrix1.getRowSize(); i++) {
        for (unsigned j = 0; j < matrix1.getRowSize(); j++) {
            (*result)(i,Col>(matrix1); // copy constructor
    for (unsigned i = 0; i < matrix1.getRowSize(); i++) {
        (*result)(i,i);
    }
    return *result;
}
在这里使用基于策略的设计的主要优势在于,您的用户可以轻松地提供自己的存储功能并进行操作。您需要做的就是给他们一个清晰的界面,以便他们知道如何制作自己的存储设备和调整操作。