问题描述
|
我想对模板类使用部分专业化,以便该模板类的所有子级都将使用该专业化。让我用一个例子解释一下:)
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;
}
在这里使用基于策略的设计的主要优势在于,您的用户可以轻松地提供自己的存储功能并进行操作。您需要做的就是给他们一个清晰的界面,以便他们知道如何制作自己的存储设备和调整操作。