5

テンプレートクラスに部分的な特殊化を使用して、そのテンプレートクラスのすべての子がその特殊化を使用できるようにします。例を挙げて説明しましょう:)

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

このクラスには、sparse、dense、diagonalなどの行列の構造を指定する子があります。

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

継承は、テンプレートの特殊化には適用されません。を呼び出すと、2番目の引数が。ではなく、であるため、matrix<int,StackDenseMatrix,3,2> matrix;の一般的なテンプレートが選択されます。これらのクラスは継承によって関連付けられていますが、違いはありません。まったく同じタイプではないため、コンパイラーはの特殊化を選択しません。matrixStackDenseMatrixBaseMatrixmatrix

あなたの問題を解決するために、私はこの場合、継承があなたに何の役にも立たないと思います。ジェネリックプログラミングでは、より適切なツールはタイプ特性、ポリシー、および概念です。この場合、同様の目標を達成するためにいくつかのタイプ特性を適用できるはずです。私が使用したいトリックの1つは、前のテンプレート引数に依存するデフォルトのテンプレート引数であり、その後、部分的な特殊化を行います。たとえば、次のようになります。

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 に答える