多个类的父类的部分专门化 [英] Partial specialization for a parent of multiple classes

查看:113
本文介绍了多个类的父类的部分专门化的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

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

此类将具有指定矩阵结构的子元素,如稀疏,密集,对角线。 。

 模板< 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-,etc ...

  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> {};但是当我写一个StackDiagonalMatrix继承自DiagonalMatrix时,它没有找到对DiagonalMatrix的专业化 - - - - - - - - - - - - - - - 它实际上没有找到专门化。

 错误:aggregate'matrix< int,StackDenseMatrix,3u,2u&矩阵'有不完整的类型,不能定义

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



非常感谢!



涉及:

 模板< 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 j = 0; 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>矩阵;
return 0;
}


解决方案

继承不适用于模板专业化。当你调用 matrix< int,StackDenseMatrix,3,2>矩阵; ,它将选择 matrix 的一般模板,因为第二个参数是 StackDenseMatrix ,而不是 BaseMatrix 。即使这些类是通过继承相关的,它没有任何区别,它们不是完全相同的类型,所以编译器不会选择 matrix



为了解决你的问题,我认为继承在这种情况下不会有任何好处。在通用编程中,更适当的工具是类型特征,策略和概念。在这种情况下,您应该能够应用一些类型 - traits以实现类似的目标。我喜欢使用的一个技巧是取决于先前的模板参数的默认模板参数,然后进行部分专门化。例如:

 枚举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;
// ..
};

//带有默认参数的常规模板:
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;

//给定参数的专用化:
template< typename T,
template< typename,unsigned,unsigned> class MatrixContainer,
unsigned Rows,unsigned Cols>
class matrix< T,MatrixContainer,Rows,Cols,DenseMatrix,GeneralMatrix> {
//当容器是密集的且具有一般结构时,矩阵的实现...
};

int main(){
matrix< int,StackDenseMatrix,3,2> M; //没有额外的参数,正确的专业化将根据StackDenseMatrix的特点进行选择。
return 0;
};

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


I want to use partial specialization for a template class so that all children of that template class will use that specialization. Let me explain it with an example :)

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

This class will have children that specify the structure of the matrix, like sparse,dense,diagonal,..

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

Then those classes will have children again that specify the storage : stack arrays, vectors, list, queues,..

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

Then there is a class Matrix, which provides all the mathematical functionality. This template class implements operator+, operator-, etc...

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

For this last class I want to write specializations like this:

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>  {};

But when I write a StackDiagonalMatrix which inherits from DiagonalMatrix, it does not find the specialization for DiagonalMatrix -- it does not find a specialization at all actually.

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

Now is there a solution for this problem? Can you write a specialization for a parent of several template classes?

Many thanks!

Full Source that is involved :

    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;
}

解决方案

Inheritance does not apply to template specializations. When you invoke matrix<int,StackDenseMatrix,3,2> matrix;, it will select the general template for matrix, because the second argument is StackDenseMatrix, not BaseMatrix. Even though those classes are related through inheritance, it doesn't make any difference, they are not of the exact same type, so the compiler won't select the specialization of matrix.

To solve your problem, I don't think inheritance will do you any good in this case. In generic programming, the more appropriate tools are type-traits, policies and concepts. In this case, you should be able to apply some type-traits to achieve similar goals. One trick I like to use is the default template argument that depends on a previous template argument, and then do a partial specialization. As follows for example:

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;
};

I have my own matrix library that heavily relies on template meta-programming and generic programming techniques along the lines of the above example to provide special implementation of matrix operations for different type of matrix structures and storage, and it works very well this way. I used to use inheritance for the different matrix types, but I have now switched to relying only on type-traits, concepts, policies and Sfinae switches, that is a much more practical solution.

这篇关于多个类的父类的部分专门化的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆