Edit:
Note that my final purpose here is not having the class working, is just learning more about templates 🙂
Suppose you have a template class which implements a vector:
template <typename T>
class Vector
{
public:
Vector(size_t dim) {
dimension = dim;
elements = new T[dim];
}
/* Here more stuff, like operator[] etc... */
private:
size_t dimension;
T * elements;
}
And suppose you want to build a matrix with it. A matrix is just a vector of vectors, thus it can be designed as follows:
template <typename T>
class Matrix : public Vector<Vector<T> >
{
/*...*/
}
And here comes trouble: In the constructor I need to provide rows and columns as parameter to the internal vectors. It should be something like
template <typename T>
Matrix<T>::Matrix (size_t ncols, size_t nrows)
: Vector<Vector<T> > /* Here I need to specify size for both
* internal and external vectors */
{
}
Obviously I cannot write Vector<Vector<T>(nrows)>(ncols), but that’s what I would need!
A possible solution would be including size inside the template:
template <typename T, size_t N>
class Vector
{
public:
Vector() {
elements = new T[N];
}
/* Here more stuff, like operator[] etc... */
private:
T * elements;
}
Hence I would no longer need constructor parameters, but this also forces me to write clumsy code with templates everywhere (by exmample, every function using a Vector should be declared as
template <typename T, size_t N>
void foo (Vector<T,N> &vec) {...}
Do you have better solutions?
EDIT:
As solution I took inspiration from Mr Fooz’s and chubsdad’s posts. That’s how I fixed the problem:
/* The RowAccess class is just an array wrapper which raises an exception
* if you go out of bounds */
template <typename T>
class RowAccess
{
public:
RowAccess (T * values, unsigned cols) : values(vals), cols(c) {}
T & operator[] (unsigned i) throw (MatrixError) {
if (i < cols) return values[i];
else throw MatrixError("Column out of bound");
}
private:
T * values;
unsigned cols;
};
template <typename T>
class Matrix
{
public:
Matrix (unsigned rows, unsigned cols) {...}
virtual ~Matrix () {...}
RowAccess<T> operator[] (unsigned row) {
if (row < rows) return RowAccess<T>(values + cols * row, cols);
else throw MatrixError("Row out of boundary");
}
private:
unsigned rows;
unsigned cols;
T * values;
};
Thanks a lot to everyone!
This isn’t what you asked, but there’s a good chance the matrix would be better of implemented as a single linear vector where you provide high-level access methods that do the indexing (e.g. elmLoc=row*ncols+col). This way you don’t need to create and initialize a vector of vectors. You also don’t need to worry about accidentally having some inner vectors of the differing size. All dense matrix implementations I have ever used use a single linear vector as the underlying implementation.