封装 ublas 并将常量引用重载到 operator()

Encapsulating ublas and overloading the const reference to the operator()

本文关键字:operator 重载 引用 ublas 常量 封装      更新时间:2023-10-16

考虑下面的玩具示例,其中我声明了一个封装来自 boost 库ublas的类:

#include <boost/numeric/ublas/matrix_sparse.hpp>
#include <iostream>
namespace ublas = boost::numeric::ublas;
class UblasEncapsulated {
public:
    ublas::compressed_matrix<float>::reference operator()(int i, int j){
        std::cout << "Non const reference" << std::endl;
        MtrUpdated_ = true;
        return mtr_(i, j);
    }
    ublas::compressed_matrix<float>::const_reference operator()(
        int i, int j) const {
        std::cout << "Const reference" << std::endl;
        return mtr_(i, j);
    }
    UblasEncapsulated() { MtrUpdated = false; }
private:
    ublas::compressed_matrix<float> mtr_(3, 3);
    bool MtrUpdated_;
};
int main() {
    UblasEncapsulated foo;
    foo(2, 0) =  1.0f;
    float const foo_float = foo(2, 0);
    return 0;
}

我期待输出

Non constant reference
Constant reference

但我得到了

Non constant reference
Non constant reference

我做错了什么?如何正确跟踪mtr_何时可以更改其值?

foo是非常量,因此将调用foo.operator()的非常量版本。 如何使用它返回的值并不重要。

如果你真的想知道MtrUpdated_只有在实际分配元素时才设置为 true,你将需要使用代理类:

class UblasEncapsulated {
public:
    class proxy {
    public:
        proxy(UblasEncapsulated* ptr, int i, int j)
            : ptr_(ptr), i_(i), j_(j)
        {}
        proxy& operator=(float f) {
            ptr_->MtrUpdated_ = true;
            ptr_->mtr_(i_, j_) = f;
            return *this;
        }
        operator float() {
            return ptr_->mtr_(i_, j_);
        }
    private:
        UblasEncapsulated* ptr_;
        int i_;
        int j_;
    };      
    proxy operator()(int i, int j) {
        return proxy(this, i, j);
    }
    ublas::compressed_matrix<float>::const_reference operator() (int i, int j) const {
        return mtr_(i, j);
    }
    UblasEncapsulated()
        : mtr_(3, 3),
          MtrUpdated_(false)
    {}
private:
    ublas::compressed_matrix<float> mtr_;
    bool MtrUpdated_;
};

现场演示

请注意,如果可以侥幸逃脱,则应避免使用代理类,因为它不能很好地处理auto或模板参数推导之类的东西。