Я пишу классы для нижних / верхних треугольных матриц (из double
s).Используя тот факт, что n*n
треугольная матрица имеет только n*(n + 1)/2
[потенциально ненулевых] элементов, внутренне я храню только это количество элементов в элементе плоского массива.
Прежде всегоУ меня есть базовый класс для "нормальных" (то есть плотных) матриц, с operator()
в качестве оператора индекса, который принимает индекс строки и индекс столбца:
class Matrix {
public:
// [...]
virtual const double &operator()(unsigned i, unsigned j);
virtual double &operator()(unsigned i, unsigned j);
// [...]
private:
std::valarray<double> data_;
std::size_t size_;
}
// [...]
const double &Matrix::operator()(unsigned i, unsigned j) {
return data_[size_*i + j];
}
Для треугольных матриц (я будувозьмем в качестве примера нижние треугольные матрицы), чтобы обеспечить тот же интерфейс, что и для регулярной матрицы, мне нужно реализовать немного другой оператор индекса:
const double &LowerTriangular::operator()(unsigned i, unsigned j) const override {
return data_[i*(i + 1)/2 + j];
}
Оператор, приведенный выше, не является полным,поскольку, если кто-то запрашивает записи, которые находятся справа от диагонали (но все еще внутри теоретической матрицы), возвращается другой (не связанный) элемент, но вместо него должно быть возвращено 0
.
Поскольку ссылки не должныЯ не могу просто связать с локальными переменными return 0
.Таким образом, как я могу добиться этого?
Мне удалось только создать локальную статическую переменную:
const double &LowerTriangular::operator()(unsigned i, unsigned j) const override {
static const double zero = 0;
if (j > i) return zero;
return data_[i*(i + 1)/2 + j];
}
Я мог бы сделать функцию возвращаемой по значению, но как насчетнеконстантная версия (когда звонящему действительно нужно изменить содержимое)?Как я могу убедиться, что вызывающая сторона не изменяет статическую переменную zero
?Это работает, но немного уродливо:
const double &LowerTriangular::operator()(unsigned i, unsigned j) const override {
static double zero = 0;
if (j > i) return zero = 0; // kind of ugly but works
return data_[i*(i + 1)/2 + j];
}
double &LowerTriangular::operator()(unsigned i, unsigned j) override {
return const_cast<double &>( const_cast<const LowerTriangular &>(*this)(i, j) );
}
Так что же является лучшим решением?