Re: for_each() and two-dimensional array
[old text removedd to make post shorter]
Ok, seems my first reply didn't make it through. At least I cannot see
it a few hours after posting so here we go again. Thanks, John, for
your valuable input! I believe I made the code a whole lot better with
your suggestions. For example, getting rid of double-storing the
number of columns of rows cleaned up alot. I haven't read the Josuttis
section you suggested yet and I know this is very lacking
implementation, but it's alot better than what I had at first. Here's
the updated code:
#ifndef MATRIXBASE_H
#define MATRIXBASE_H
#include <cassert>
template<typename T>
class MatrixBase
{
public:
MatrixBase(int num_rows, int num_columns)
: num_rows_(num_rows), num_columns_(num_columns) {}
virtual ~MatrixBase()
{
/* TODO: Deallocate memory. */
}
/* Also handle the rule of three... */
virtual void allocate()
{
assert(num_rows_ > 0 && num_columns_ > 0);
tiles_ = new T**[num_rows_];
for (int y = 0; y < num_rows_; ++y)
{
tiles_[y] = new T*[num_columns_];
}
}
class MatrixIterator
{
public:
MatrixIterator()
: matrix_(0), row_(-1), column_(-1) {}
friend class MatrixBase;
/*
* If we don't return a reference to a pointer, we can't do:
*itr = new Foo(bar);
*/
T *& operator*()
{
if (row_ < 0 || row_ >= matrix_->num_rows_ ||
column_ < 0 || column_ > matrix_->num_columns_)
throw; // FIXME
return matrix_->tiles_[column_][row_];
}
MatrixIterator& operator++()
{
if (row_ == matrix_->num_rows_ - 1 && column_ == matrix_-
num_columns_ - 1)
{
/*
* Now when row_ == matrix_->num_rows_ and column_ ==
matrix_->num_columns_
* that means we are at the end.
*/
++row_;
++column_;
}
else if (column_ == matrix_->num_columns_ - 1)
{
++row_;
column_ = 0;
}
else
{
++column_;
}
/* Maybe add special case for if operator++() is called on an
* end() iterator? */
return *this;
}
/* MSVC++ wants a typename here or it will issue a warning. */
bool operator!=(const typename MatrixBase::MatrixIterator& rhs)
const
{
return
matrix_ != rhs.matrix_ || row_ != rhs.row_ ||
column_ != rhs.column_;
}
/* MSVC++ wants a typename here or it will issue a warning. */
bool operator==(const typename MatrixBase::MatrixIterator& rhs)
const
{
return !(*this != rhs);
}
private:
MatrixIterator(MatrixBase *matrix, int row = 0, int column = 0)
: matrix_(matrix), row_(row), column_(column) {}
MatrixBase *matrix_;
int row_;
int column_;
};
MatrixIterator begin()
{
return MatrixIterator(this);
}
MatrixIterator end()
{
return MatrixIterator(this, num_rows_, num_columns_);
}
protected:
T ***tiles_;
int num_rows_;
int num_columns_;
};
#endif
TileMatrix.h
#ifndef TILEMATRIX_H
#define TILEMATRIX_H
#include "MatrixBase.h"
#include <iostream>
class Tile
{
public:
Tile(int x, int y) : x_(x), y_(y) {}
friend std::ostream& operator<<(std::ostream& os, const Tile& rhs)
{
os << "(x, y) = (" << rhs.x_ << ", " << rhs.y_ << ")";
return os;
}
private:
int x_, y_;
};
class TileMatrix : public MatrixBase<Tile>
{
public:
TileMatrix(int rows, int columns) : MatrixBase<Tile>(rows, columns)
{ allocate(); }
virtual ~TileMatrix() {}
virtual void allocate()
{
MatrixBase<Tile>::allocate();
/* We could use iterators here but I want call the Tile
constructor
* with its index in the matrix. */
for (int x = 0; x < num_columns_; ++x)
{
for (int y = 0; y < num_rows_; ++y)
{
tiles_[y][x] = new Tile(x, y);
}
}
/*
* Iterator version:
*
* for (MatrixBase<Tile>::MatrixIterator itr = begin(); itr !=
end(); ++itr)
* {
* *itr = new Tile(foo, bar);
* }
*/
}
};
#endif
Does it look better? One thing that worries me is if I should be more
"helpful" if the user calls operator++() on an iterator that is
already at the end?
- Eric