错误:没有匹配的构造函数,用于初始化Matrix_ref <...>

时间:2018-11-26 19:39:34

标签: c++

我正在学习C ++,所以请耐心等待我。

这是我的矩阵课

template<class T = double> class Matrix {

    using sequence_type = std::vector<T>;

public:

    ... some methods and constructors

    Matrix_ref<T> col(Index i_) { if (i_ < 0 || i_ > r) _error("out_of_bound"); return Matrix_ref<T>(elems.data(), Matrix_slice(i_, r, c), r); }
    Matrix_ref<T> row(Index i_) { if (i_ < 0 || i_ > c) _error("out_of_bound"); return Matrix_ref<T>(elems.data(), Matrix_slice(i_ * c, c, 1), c); }

    const Matrix_ref<T> col(Index i_) const { if (i_ < 0 || i_ > r) _error("out_of_bound"); return Matrix_ref<T>(elems.data(), Matrix_slice(i_, r, c), r); }
    const Matrix_ref<T> row(Index i_) const { if (i_ < 0 || i_ > c) _error("out_of_bound"); return Matrix_ref<T>(elems.data(), Matrix_slice(i_ * c, c, 1), c); }

    Matrix_ref<T> operator[](Index r_) { return row(r_); }


private:
    sequence_type elems;
    Index r;
    Index c;

    ...other methods

};

这是一个结构,可返回一行中元素的正确索引(实际上是计算“步幅”)

struct Matrix_slice {

    Matrix_slice(Index first_, Index size_, Index stride_) : first(first_), size(size_), stride(stride_) {}

    const Index first;
    const Index size;
    const Index stride;

    Index operator()(Index i) { return first + stride * i; }
    const Index operator()(Index i) const { return first + stride * i; }
};

这是对矩阵的“引用”。如果对矩阵使用[]运算符,则会得到matrix_ref。

template<class T = double> class Matrix_ref {

public:
    Matrix_ref(T* elems_, Matrix_slice slice_, Index ref_size_) : elems(elems_), slice(slice_), ref_size(ref_size_) {}

    T& at(Index i) { if (i < 0 || i >= ref_size) _error("out_of_bound"); return elems[slice(i)]; }
    const T& at(Index i) const { if (i < 0 || i >= ref_size) _error("out_of_bound"); return elems[slice(i)]; }

    T& operator[](Index i) { return elems[slice(i)]; }
    const T operator[](Index i) const { return elems[slice(i)]; }

    constexpr Index size() const { return ref_size; }

private:
    T* elems;
    const Matrix_slice slice;
    const Index ref_size;

};

这是运算符*的定义:

template<class T> Matrix<T> operator*(const Matrix<T>& a, const Matrix<T>& b) {
    if (a.cols() != b.rows()) _error("Matrix size mismatch");
    Matrix<T> res(a.rows(), b.cols());
    for (Index i = 0; i < res.rows(); ++i)
        for (Index j = 0; j < res.cols(); ++j)
            res.at(i, j) = a.row(i) * b.col(j);
    return res;
}

问题在这里->运算符*(const Matrix&a,const Matrix&b) 如果我用const Matrix&a和const ... b声明此运算符,则不起作用,但是如果我不使用const关键字声明,则它起作用。但是我认为最好使用const。我该如何解决?我认为问题在于Matrix_ref尚未将T *元素声明为const。如果我将其声明为const,则可以使用,但不能修改Matrix。由于此行“ res.at(i,j)= a.row(i)* b.col(j);”导致在Matrix类的行/列方法返回时出现错误。在重载运算符*函数中。

完整代码:https://github.com/H0lm3s/Matrix/tree/master

1 个答案:

答案 0 :(得分:1)

正如您所说的,问题出在 constness

const Matrix_ref<T> col(Index i_) const 
{ 
        if (i_ < 0 || i_ > r) _error("out_of_bound"); 
        return Matrix_ref<T>(elems.data(), Matrix_slice(i_, r, c), r);  // <-- 
}

当您从 const 方法调用elems.data()时,vector<T>::data()返回const T*, 编译器抱怨,因为无法将const T*分配给T*-存在风险 修改数据。但是,您知道rowcol方法会返回 代理类const Matrix_ref<T> const 对象,因此您可以使用 const_castelemes.data()中删除常量,代理类的实例将保留指向T的指针,并且由于返回的对象仅被限定为const const 方法,这样可以防止在使用代理类时修改Matrix中的数据。 在这种情况下,使用const_cast是安全的,因此可以如下更改rowcol成员函数:

const Matrix_ref<T> col(Index i_) const { 
    if (i_ < 0 || i_ > r) _error("out_of_bound"); 
    return Matrix_ref<T>( const_cast<T*>(elems.data()) , Matrix_slice(i_, r, c), r); 
}                      // ^^^