【问题标题】:C++ template matrix class - square matrix specialisationC++模板矩阵类——方阵特化
【发布时间】:2016-06-15 19:15:43
【问题描述】:

我正在创建一个简单的 C++ 矩阵模板类,其定义如下:

template<uint n, uint m, typename T = double>
class Matrix {
private:
    T data[n][m];

    static Matrix<n, m, T> I;

public:
    Matrix();
    Matrix(std::initializer_list<T> l);

    T& at(uint i, uint j);  // one-based index
    T& at_(uint i, uint j); // zero-based index

    template<uint k> Matrix<n, k, T> operator*(Matrix<m, k, T>& rhs);
    Matrix<m, n, T> transpose();
    Matrix<n, m, T> operator+(const Matrix<n, m, T>& rhs);
    Matrix<n, m, T>& operator+=(const Matrix<n, m, T>& rhs);
    Matrix<n, m, T> operator-(const Matrix<n, m, T>& rhs);
    Matrix<n, m, T>& operator-=(const Matrix<n, m, T>& rhs);
    Matrix<n, m, T> operator*(const T& rhs);
    Matrix<n, m, T>& operator*=(const T& rhs);
    Matrix<n, m, T> operator/(const T& rhs);
    Matrix<n, m, T>& operator/=(const T& rhs);

    static Matrix<n, m, T> identity();
};

uint 被定义为unsigned int

最终函数Matrix&lt;n, m, T&gt; identity() 旨在返回静态I 成员,它是使用基本单例模式的单位矩阵。显然,单位矩阵只为方阵定义,所以我尝试了这个:

template<uint n, typename T>
inline Matrix<n, n, T> Matrix<n, n, T>::identity() {
    if (!I) {
        I = Matrix<n, n, T>();
        for (uint i = 0; i < n; ++i) {
            I.at(i, i) = 1;
        }
    }
    return I;
}

这给出了错误C2244 'Matrix&lt;n,n,T&gt;::identity': unable to match function definition to an existing declaration

我的印象是我可以对模板进行某种特殊化,其中列数和行数相等。我不确定这是否可能,但非常感谢您的帮助。

【问题讨论】:

    标签: c++ templates matrix static


    【解决方案1】:

    试试这个:

    static Matrix<n, m> identity() {
        static_assert(n == m, "Only square matrices have a identity");
        return {}; //TODO
    }
    

    见:http://cpp.sh/7te2z

    【讨论】:

    • 那行不通。使用 n != m 实例化 Matrix 将导致实例化函数签名,当 n != m 时,该函数签名是非良构的。你必须更微妙一点。
    • @Brian 你是对的,它不能编译。我不明白为什么 SFINAE 不参与,只是忽略了该功能。无论如何,编辑了我的答案,static_assert 似乎有效,甚至给出了更好的错误消息
    • SFINAE 仅在模板参数推导过程中发生替换失败时发生。
    • 谢谢,我还没有真正遇到过 static_assert :)
    【解决方案2】:

    模板类的Partial specialization 可以用于整个类,但不能用于其单个成员。

    部分特化的成员与主要的成员无关 模板。

    这就是编译错误的原因。

    当然,将整个 Matrix 模板专门用于方阵情况是没有意义的。 @tkausl 已经回答了如何使 identity() 函数仅适用于方阵类型。

    但是,我想提请您注意您在实施Matrix 时遇到的几个问题:

    1. 矩阵数据是一个普通数组(而不是动态分配的数组或std::vector)。这有以下缺点:

      • sizeof(Matrix&lt;N, M, T&gt;) == sizeof(T)*N*M。在堆栈上分配大矩阵可能会导致stack overflow
      • 无法利用移动语义(因为数据与矩阵对象密不可分)。

      但是,如果矩阵维度在编译时常数处是固定的,那么它们很可能是很小的数字。如果是这样,支付动态分配的成本可能确实是不合理的。

    2. identity() 按值返回其结果(而不是通过常量引用)。

    3. I(单位矩阵)是该类的静态成员。最好在identity() 函数中将其设为静态变量。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-06-23
      • 1970-01-01
      • 2013-11-22
      • 1970-01-01
      • 2017-08-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多