5

我想对模板类使用部分特化,以便该模板类的所有子级都使用该特化。让我用一个例子来解释:)

template < typename T, unsigned int rows, unsigned int cols>
class BaseMatrix {...};

此类将具有指定矩阵结构的子级,例如稀疏,密集,对角线,..

template < typename T, unsigned int rows, unsigned int cols>
class DiagonalMatrix : public BaseMatrix<T,rows,cols>{..}

然后这些类将再次具有指定存储的子类:堆栈数组,向量,列表,队列,..

template < typename T, unsigned int rows, unsigned int cols>
class StackDiagonalMatrix : public DiagonalMatrix<T, rows, cols> {..}

然后是一个类 Matrix,它提供了所有的数学功能。这个模板类实现了operator+、operator-等...

   template <typename T, 
             template<typename, unsigned, unsigned> class MatrixContainer,
             unsigned Rows, 
             unsigned Cols>
    class matrix;

对于最后一堂课,我想写这样的专业:

template <typename T,unsigned Rows, unsigned Cols>
class matrix<T, BaseMatrix, Rows, Cols> {};

template <typename T,unsigned Rows, unsigned Cols>
class matrix<T, DiagonalMatrix, Rows, Cols>  {};

但是当我编写一个继承自 DiagonalMatrix 的 StackDiagonalMatrix 时,它没有找到 DiagonalMatrix 的特化——它实际上根本没有找到特化。

error: aggregate ‘matrix<int, StackDenseMatrix, 3u, 2u> matrix’ has incomplete type and cannot be defined

现在有解决这个问题的方法吗?你能为几个模板类的父类写一个特化吗?

非常感谢!

涉及的完整来源:

    template <typename T, unsigned int rows, unsigned int cols>
    class BaseMatrix {
    protected:
        BaseMatrix(){};
        static const unsigned rowSize = rows;
        static const unsigned colSize = cols;
    };

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

    };

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

    public:
        typedef T                                           value_type;

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

    template<typename value_type, unsigned int rows, unsigned int cols>
    StackDenseMatrix<value_type, rows,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, template<typename, unsigned, unsigned> class MatrixContainer ,unsigned Rows, unsigned Cols>
    class matrix;

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

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

2 回答 2

4

继承不适用于模板特化。当你调用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 Rows, unsigned Cols, 
          MatrixStorage Storage = MatrixContainer<T,Rows,Cols>::Storage,
          MatrixStructure Structure = MatrixContainer<T,Rows,Cols>::Structure>
class matrix;

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

int main() {
  matrix<int,StackDenseMatrix,3,2> M; //no extra arguments, and the right specialization will be selected based on the traits of StackDenseMatrix.
  return 0;
};

我有自己的矩阵库,它严重依赖于模板元编程和通用编程技术,按照上述示例的思路,为不同类型的矩阵结构和存储提供矩阵运算的特殊实现,并且它以这种方式工作得很好。我曾经对不同的矩阵类型使用继承,但现在我已经切换到仅依赖类型特征、概念、策略和 Sfinae 开关,这是一个更实用的解决方案。

于 2011-05-27T17:50:16.523 回答
0

要解决您的问题,您可以使用基于策略的设计。您可以创建 Storage 和 Shape 的实例策略类。

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,Shape1,Storage1,Row1,Col1> matrix1,Matrix<T,Shape,Storage,Row,Col> matrix2);

    template <typename T1, typename Shape1, typename Storage1, unsigned Row1, unsigned Col1>
    friend Matrix<T1,Diagonal,Storage1,Row1,Col1>& operator += (Matrix<T1,Diagonal,Storage1,Row1,Col1> matrix1,Matrix<T,Diagonal,Storage,Row,Col> matrix2);

    template <typename T1, typename Shape1, typename Storage1, unsigned Row1, unsigned Col1>
    friend Matrix<T,Shape,Storage,Row,Col>& operator + (Matrix<T,Shape,Storage,Row,Col> matrix1, Matrix<T,Shape,Storage,Row,Col> matrix2);

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

// general template function
template <typename T, typename Shape, typename Storage, unsigned Row, unsigned Col>
Matrix<T,Shape,Storage,Row,Col>& operator + (Matrix<T,Shape,Storage,Row,Col> matrix1, Matrix<T,Shape,Storage,Row,Col> matrix2) {
    Matrix<T,Shape,Storage,Row,Col>* result = new Matrix<T,Shape,Storage,Row,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, typename Shape, typename Storage, unsigned Row, unsigned Col>
Matrix<T,Diagonal,Storage,Row,Col>& operator + (Matrix<T,Diagonal,Storage,Row,Col> matrix1, Matrix<T,Diagonal,Storage,Row,Col> matrix2) {
    Matrix<T,Shape,Storage,Row,Col>* result = new Matrix<T,Shape,Storage,Row,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, typename Shape, typename Storage, unsigned Row, unsigned Col>
Matrix<T,Shape,Storage,Row,Col>& operator += (Matrix<T,Shape,Storage,Row,Col> matrix1,Matrix<T,Shape,Storage,Row,Col> matrix2)  {
    Matrix<T,Shape,Storage,Row,Col>* result = new Matrix<T,Shape,Storage,Row,Col>(matrix1); // copy constructor
    for (unsigned i = 0; i < matrix1.getRowSize(); i++) {
        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, typename Shape, typename Storage, unsigned Row, unsigned Col>
Matrix<T,Diagonal,Storage,Row,Col>& operator += (Matrix<T,Diagonal,Storage,Row,Col> matrix1,Matrix<T,Diagonal,Storage,Row,Col> matrix2) {
    Matrix<T,Shape,Storage,Row,Col>* result = new Matrix<T,Shape,Storage,Row,Col>(matrix1); // copy constructor
    for (unsigned i = 0; i < matrix1.getRowSize(); i++) {
        (*result)(i,i) = matrix1.getValue(i,i) + matrix2.getValue(i,i);
    }
    return *result;
}

在这里使用基于策略的设计的主要优点是您的用户可以轻松地提供他们自己的存储设施和形状操作。您需要做的就是给他们一个清晰的界面,以便他们知道如何制作自己的存储设施和塑造运营。

于 2011-05-28T20:26:34.483 回答