首页 > 解决方案 > 错误:没有用于初始化 'Matrix_ref<...>' 的匹配构造函数

问题描述

我正在学习 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;

};

这是 operator* 的定义:

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

问题在这里 -> operator*(const Matrix& a, const Matrix& b) 如果我用 const Matrix& a 和 const...b 声明这个运算符,它不起作用,但如果我声明没有 const 关键字,它会起作用。但我认为使用 const 会更好。我该如何解决?我认为问题在于 Matrix_ref 没有将 T* elems 声明为 const。如果我将它声明为 const,它可以工作,但我不能修改 Matrix。我在返回 Matrix 类中的 row/col 方法时遇到错误,这是由这一行“res.at(i, j) = a.row(i) * b.col(j);”引起的 在重载 operator* 函数中。

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

标签: c++

解决方案


正如你所说,问题在于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);  // <-- 
}

当您elems.data()const方法vector<T>::data()返回调用时const T*,编译器会抱怨,因为const T*无法分配给T*- 修改数据的风险。但是,您知道rowandcol方法返回 代理类的const对象, const Matrix_ref<T>因此您可以用来 const_cast从 中删除 const elemes.data(),代理类的实例将保留指向 的指针T,并且由于返回的对象是合格的,因为const只能在此对象上调用const方法,因此防止在Matrix您使用代理类时修改数据。在这种情况下使用是安全的,因此您可以按如下const_cast方式更改row和成员函数:col

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); 
}                      // ^^^ 

推荐阅读