【问题标题】:Matrix Multiplication using Templates in c++在 C++ 中使用模板进行矩阵乘法
【发布时间】:2015-11-08 03:27:20
【问题描述】:

我正在尝试将类模板用于矩阵。但是我遇到了矩阵乘法的问题。

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

当涉及到将两个 mat4(4x4 矩阵)相乘时,如下所示:

m_model = (m_view*m_model);

它给出了错误Invalid operands to binary expression ('mat4' (aka 'Matrix&lt;float, 4, 4&gt;') and 'mat4')。在线查看后,我可以看到这不是函数模板的预期用途,因为您必须在调用模板参数时分配。有没有一种类似于我最初打算的方法,即根据函数的第二个参数自动分配模板参数?

这里分别是MatrixBase和Matrix(aka mat4)的定义:

矩阵基础

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

【问题讨论】:

  • 您可以考虑使用库来执行此操作,这样您就不必重新发明轮子。试试 Eigen (eigen.tuxfamily.org)
  • 也为我工作,没有那个 MatrixBase,但在 Matrix 类中定义 array&lt;array&lt;T, N&gt;, M&gt; i;
  • 好的,这很令人担忧。但是我确实有另一个 mat4 类定义的模板,可能是问题所在。虽然当这个函数是 MatrixBase 类的一部分时我得到了同样的错误。

标签: c++ function templates matrix


【解决方案1】:

除非您这样做是为了练习(这将是一个很好的练习),否则我只会使用现有的线性代数库来实现矩阵向量运算。如犰狳:http://arma.sourceforge.net/

【讨论】:

  • 我认为你可能是对的。不过很遗憾,我的数学“图书馆”非常根深蒂固。我正在考虑使用 GLM,它特定于 OpenGL,并且是用 c++ 编写的,想不出不使用它的理由。
  • 挣脱那个壕沟!重构您的库,以便您可以为特定操作提供适配器:、^、% 等……您的劳动成果将是压倒性的。想象一下,允许您的客户端代码仅通过提供一个调用外部库 *hint hint ArrayFire 或 Armadillo 的模板特化来实现 GPU 矩阵乘法。
【解决方案2】:

不是答案,而是分享对我有用的东西并确保定义乘法运算符的方法的正确性:

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

【讨论】:

  • 好吧,除了 mat4 之外,我已经让它对我有用。正是 mat4 的定义覆盖了通用模板类。问题还在于使用 MatrixBase 来定义 Vector。 MatrixBase 取模板中的 ChildT,即继承 MatrixBase 的类。所以我认为很明显在MatrixBase中定义乘法是很困难的,因为ChildT不能为不同顺序的新矩阵重新定义。
  • @James:你为什么不发布mat4的定义?
  • @Cornstalks 我认为这无关紧要,只是说它没有定义 * 运算符。正如您从上面看到的,我现在正在切换到 glm 库。但如果它对其他人有帮助,我将编辑我的问题以包括 MatrixBase 和 mat4。
  • @James:好吧,事实证明它实际上是非常相关的,因为你已经专门化了这个类(这就是导致错误的原因)。专业化与其非专业化版本没有任何共享(它们是不同的类),这意味着Matrix&lt;T, 4, 4&gt; 没有operator*,因为您没有在专业化中声明/定义。这就是 StackOverflow 对 Minimal, Complete, and Verifiable examples 大加关注的原因,因为这些小细节通常非常重要,除非有一个完整的示例,否则我们无能为力。
  • @Cornstalks 即使它是一个简单的 typedef,如果我没记错的话。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-05-30
  • 2020-10-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-01-30
  • 1970-01-01
相关资源
最近更新 更多