2016-10-08 4 views
1

私はOpenGLESプロジェクトのMathモジュールを作成しています。 私は、一般的なサイズC++ 11テンプレートの継承をキャストできません

template <unsigned int N> 
class MatrixN { 

    public: 
     float m[N*N]; 

     MatrixN(){} 
     virtual ~MatrixN(){} 

     void identify(); 

     MatrixN& operator=(const MatrixN& b); 
}; 

template <unsigned int N> 
MatrixN<N> operator*(const MatrixN<N>& a, const MatrixN<N>& b); 


//CPP file implementation 
template<unsigned int N> 
MatrixN<N> operator*(const MatrixN<N>&a, const MatrixN<N> &b) { 
    MatrixN<N> matrix; 

    for(unsigned int i = 0; i < N; i++){ 
     for(unsigned int j = 0; j < N; j++){ 
      matrix.m[i * N + j] = 0; 
      for(unsigned int z = 0; z < N; z++){ 
       matrix.m[i * N + j] += a.m[i * N + z] * b.m[z * N + j]; 
      } 
     } 
    } 

    return matrix; 
} 

用フロート行列を管理するためのクラスを書いて、私は3x3の行列を管理するためのサブクラスを作成し、私はこの操作を実行するのはなぜ

class Matrix3 : public MatrixN<3> { 

    public: 
     void rotateX(const float radians); 
     void rotateY(const float radians); 
     void rotateZ(const float radians); 
}; 

//Rotations instances of Matrix3 
Matrix3 rotation = this->rotation * input.rotation; 

コンパイル時にこのエラーが発生しますか?

no viable conversion from 'MatrixN<3U>' to 'const Matrix3' 
+0

'operator *'は 'MatrixN 'を返すので、 'Matrix3'ではありません。 – tkausl

+0

どのように動作するのですか? –

+0

input.rotationはMatrixN <3>のタイプですか? – billz

答えて

1

それが原因で乗算演算の戻りですこのコードは動作するかもしれ

class Matrix3 : public MatrixN<3> { 

    public: 
     Matrix3 (const MatrixN<3>& mat){/*set internal values*/} 
     void rotateX(const float radians); 
     void rotateY(const float radians); 
     void rotateZ(const float radians); 
}; 
+0

これはうまくいった!ありがとうございました! –

0

問題はoperator*の結果タイプがMatrixN<N>ですがrotationのタイプはMatrix3であり、これは意気消沈になるので、暗黙的なキャストが動作しないということです。

Matrix3入出力の場合は、operator*を上書きすることができます。ヘルパー関数を使用すると、コードを再利用したい場合には余裕ができます。たとえば:

template<MatrixType> 
MatrixType multiple(const MatrixType& a, const MatrixType& b, size_t N) 
{ 
    MatrixType matrix; 

    for(unsigned int i = 0; i < N; i++) 
    { 
     for(unsigned int j = 0; j < N; j++) 
     { 
      matrix.m[i * N + j] = 0; 
      for(unsigned int z = 0; z < N; z++) 
      { 
       matrix.m[i * N + j] += a.m[i * N + z] * b.m[z * N + j]; 
      } 
     } 
    } 

    return matrix; 
} 

Matrix3 operator*(const Matrix3& a, const Matrix3& b) 
{ 
    return multiple<Matrix3>(a, b, 3); 
} 

オーバーフローを回避するために、任意の保護がないため、これは少し危険なことができることに注意してください、そうmultiple機能の「ユーザ」は注意する必要があります。

0

乗算演算子はMatrixN<N>で実装されています。あなたの派生型Matrix3はすぐにそれらの1つではありませんが、それらの1つがベースとしてあります。したがって、演算子を呼び出すための派生から基底への変換はまだあります。返される型は、すぐに必要な型ではありません。

template<typename Matrix, 
     typename = std::enable_if_t<std::is_base_of<MatrixN<Matrix::size>, Matrix>::value>> 
Matrix operator*(const Matrix&a, const Matrix &b) { 
    constexpr unsigned N = Matrix::size; 
    Matrix matrix; 

    for(unsigned int i = 0; i < N; i++){ 
     for(unsigned int j = 0; j < N; j++){ 
      matrix.m[i * N + j] = 0; 
      for(unsigned int z = 0; z < N; z++){ 
       matrix.m[i * N + j] += a.m[i * N + z] * b.m[z * N + j]; 
      } 
     } 
    } 

    return matrix; 
} 

が静的​​のサイズNを決定するには:

あなたは、引数として任意の型を取り、この型を返し、その後、本当にMatrixN<N>から派生しているタイプを取るだけに、それを制約するためにあなたの乗算演算子を定義することができます行列、クラステンプレートは、例えば、ネストされた定数式の値sizeを持っている必要があります:

0

:とこの場合ではないMatrix3

では、あなたが(ないテスト)MatrixN<3>


コードを受け入れることMatrix3でコンストラクタを作成することができます。しかし、これは非常に非常に危険です知っておくべきです。

MatrixN<3> tmp_scoped_var = this->rotation * input.rotation; 
Matrix3 &rotation = reinterpret_cast<Matrix3 &>(tmp_scoped_var); 
rotation.rotateX(1.1); // Call the method of B 

tmp_scoped_varのでMatrixN<N>operator *によって返されたデータを保持します。したがって、メモリはスコープの外にある間解放されます。このコードは、MatrixN<N>変数のMatrix3のメソッドを使用してコンパイルを強制します。 Matrix3MatrixN<N>のメモリレイアウトは同一です。そうでない場合は、セグメントの障害によりプログラムがクラッシュする可能性があります。


あなたのコードによると、あなたはテンプレートパラメータN3に等しくしながら、いくつかの特定のメソッドを追加することを望むかもしれません。したがって、クラステンプレートの特殊化を使用できます。

template <> 
class MatrixN<3> { 

    public: 
     float m[3*3]; 

     MatrixN(){} 
     virtual ~MatrixN(){} 

     void identify(); 

     MatrixN& operator=(const MatrixN<3>& b); 

    public: 
     void rotateX(const float radians); 
     void rotateY(const float radians); 
     void rotateZ(const float radians); 
}; 
関連する問題