2015-11-07 35 views
0

我想將類模板用於矩陣。但是我遇到了矩陣乘法的問題。在C++中使用模板的矩陣乘法

template<typename T, unsigned int N, unsigned int M> 
class Matrix : public MatrixBase<Matrix<T, N, M>, T, N, M> { 

    template<unsigned int K> 
    friend Matrix<T, N, K> operator*(const Matrix<T, N, M>& m1, const Matrix<T, M, K>& m2) { 
     Matrix<T, N, K> ret; 
     for (unsigned int n = 0; n != N; n++) { 
      for (unsigned int k = 0; k != K; k++) { 
       ret.i[n][k] = 0; 
       for (unsigned int m = 0; m != M; m++) { 
        ret.i[n][k] += m1.i[n][m]*m2.i[m][k]; 
       } 
      } 
     } 
     return ret; 
    } 
}; 

當再談到乘以2 MAT4的(4X4矩陣),像這樣:

m_model = (m_view*m_model); 

它給人的錯誤Invalid operands to binary expression ('mat4' (aka 'Matrix<float, 4, 4>') and 'mat4')。在網上看了一下,我可以看到這不是函數模板的預期用途,因爲您必須在調用模板參數時進行分配。有沒有類似於我第一次打算的方法,即基於函數的第二個參數自動分配模板參數?

這裏有MatrixBase和Matrix(又名MAT4)分別的定義:

MatrixBase

template<typename T , unsigned int M> 
struct ComponentColumn{ 
    T& operator[](int m) { 
     return i[m]; 
    } 

    const T& operator[](int m) const { 
     return i[m]; 
    } 


    T i[M]; 
}; 


//-----------MATRIXBASE----------- 
template <typename ChildT, typename T, unsigned int N, unsigned int M> 
class MatrixBase { 
public: 
    MatrixBase() {} 

    MatrixBase<ChildT, T, N, M> operator*=(const MatrixBase<ChildT, T, N, M>& m1) { 
     MatrixBase<ChildT, T, N, M> ret; 
     for (unsigned int n = 0; n != N; n++) { 
      for (int k = 0; k != M; k++) { 
       ret.i[n][k] = 0; 
       for (unsigned int m = 0; m != M; m++) { 
        ret.i[n][k] += (*this).i[n][m]*m1.i[m][k]; 
       } 
      } 
     } 

     *this = ret; 

     return ret; 
    } 

    MatrixBase<ChildT, T, N, M> operator+(const MatrixBase<ChildT, T, N, M>& m1) { 
     MatrixBase<ChildT, T, N, M> ret; 
     for (int n = 0; n != N; n++) { 
      for (int m = 0; m != M; m++) { 
       ret.i[n][m] = i[n][m]; 
      } 
     } 
     return ret; 
    } 

    ComponentColumn<T, M>& operator[](int n) { 
     return this->i[n]; 
    } 


    const ComponentColumn<T, M>& operator[](int n) const { 
     return this->i[n]; 
    } 

    explicit operator T*() { 
     return &(*this)[0][0]; 
    } 

protected: 
    ComponentColumn<T, M> i[N]; 
}; 

MAT4

template<typename T> 
class Matrix<T, 4, 4> : public MatrixBase<Matrix<T, 4, 4>, T, 4, 4> { 
public: 
    Matrix<T, 4, 4>() { 
     for (unsigned int n = 0; n != 4; n++) { 
      for (unsigned int m = 0; m != 4; m++) { 
       if (n == m) { 
        (*this)[n][m] = 1; 
       } else { 
        (*this)[n][m] = 0; 
       } 
      } 
     } 
    } 

    Matrix<T, 4, 4>(const Matrix<T, 3, 3>& m) { 
     (*this)[0][0] = m[0][0]; (*this)[1][0] = m[1][0]; (*this)[2][0] = m[2][0]; (*this)[3][0] = 0; 
     (*this)[0][1] = m[0][1]; (*this)[1][1] = m[1][1]; (*this)[2][1] = m[2][1]; (*this)[3][1] = 0; 
     (*this)[0][2] = m[0][2]; (*this)[1][2] = m[1][2]; (*this)[2][2] = m[2][2]; (*this)[3][2] = 0; 
     (*this)[0][3] = 0; (*this)[1][3] = 0; (*this)[2][3] = 0; (*this)[3][3] = 1; 
    } 

    static Matrix<T, 4, 4> Translate(T x, T y, T z); 
    static Matrix<T, 4, 4> Translate(const vec3& v); 
    static Matrix<T, 4, 4> Scale(T s); 
    static Matrix<T, 4, 4> Rotate(T degrees); 
    static Matrix<T, 4, 4> Frustum(T left, T right, T bottom, T top, T near, T far); 

    explicit operator Matrix<T, 3, 3>() { 
     Matrix<T, 3, 3> ret; 
     for (int n = 0; n != 3; n++) { 
      for (int m = 0; m != 3; m++) { 
       ret[n][m] = (*this)[n][m]; 
      } 
     } 

     return ret; 
    } 

    Matrix<T, 4, 4> Transpose() { 
     Matrix<T, 4, 4> ret = Matrix<T, 4, 4>(); 
     for (unsigned int n = 0; n != 4; n++) { 
      for (unsigned int m = 0; m != 4; m++) { 
       ret.i[n][m] = this->i[m][n]; 
      } 
     } 
     *this = ret; 
     return ret; 
    } 

    Matrix<T, 4, 4> Inverse(); 
}; 
+1

你可能會考慮使用庫來做到這一點,所以你不必重新發明輪子。嘗試Eigen(http://eigen.tuxfamily.org/) –

+0

[我無法重現您的錯誤](https://ideone.com/oNn4mI)。 – Cornstalks

+0

也爲我工作,沒有該MatrixBase,但在Matrix類中定義'array ,M> i;'。 –

回答

1

不是答案,而是要分享給我什麼工作,確保定義乘法運算符的方法的正確性:

template<typename T, unsigned int N, unsigned int M> 
class Matrix { 
public: 
    template<unsigned int K> 
    friend Matrix<T, N, K> operator*(const Matrix<T, N, M>& m1, const Matrix<T, M, K>& m2) { 
    Matrix<T, N, K> ret; 
    for (unsigned int n = 0; n != N; n++) { 
     for (unsigned int k = 0; k != K; k++) { 
     ret.i[n][k] = 0; 
     for (unsigned int m = 0; m != M; m++) { 
      ret.i[n][k] += m1.i[n][m] * m2.i[m][k]; 
     } 
     } 
    } 
    return ret; 
    } 
    array<array<T, M>, N> i; 
}; 

int main() { 
    Matrix<float, 4, 6> m1; Matrix<float, 6, 10> m2; 
    auto m3 = (m1 * m2); 
    cout << m3.i[0][0] << m3.i[3][9] << "\n"; 
    system("pause"); 
} 
+0

好吧,我已經爲我的工作,除了mat4的一切。這是mat4的定義覆蓋了一般模板類。問題在於使用MatrixBase來定義Vector。 MatrixBase在模板中使用ChildT,該模板是繼承MatrixBase的類。所以我認爲很明顯,在MatrixBase中很難定義乘法,因爲不能以不同的順序爲新的Matrix重新定義ChildT。 – James

+0

@詹姆斯:爲什麼你沒有發佈'mat4'的定義? – Cornstalks

+0

@Cornstalks我不認爲它是相關的,只是說它沒有定義*運算符。正如你從上面看到的,我現在正在切換到glm庫。但如果它幫助別人,我會編輯我的問題,包括MatrixBase和mat4。 – James

2

除非你正在做這個練習,這將是一個很好的練習,否則我只會使用一個現有的線性代數庫來實現矩陣向量操作。如Armadillo:http://arma.sourceforge.net/

+0

我認爲你可能是對的。這是一個恥辱,但我有我的數學「圖書館」非常穩固。我想到GLM,它是特定於OpenGL和用C++編寫的,不能想到不使用它的理由。 – James

+0

擺脫這種壕溝!重構您的圖書館,以便您可以爲特定的操作提供適配器:*,^,%等... 您的勞動成果將壓倒一切。想象一下,讓您的客戶端代碼實現GPU矩陣乘法只需提供一個模板專門化,該模板專門化調用外部庫*提示提示ArrayFire或Armadillo *。 –