Edit: Обратите внимание, что моя конечная цель здесь не имеющий класс работает, просто узнать больше о шаблонах :-)Вложенные шаблоны и конструктор
Предположим, у вас есть шаблонный класс, который реализует вектор:
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;
}
И предположим, что вы хотите построить с ним матрицу. Матрица просто вектор векторов, таким образом, он может быть сконструирован следующим образом:
template <typename T>
class Matrix : public Vector<Vector<T> >
{
/*...*/
}
И здесь приходит проблему: В конструкторе мне нужно предоставить строки и столбцы в качестве параметра для внутренних векторов. Это должно быть что-то вроде
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 */
{
}
Очевидно, что я не могу писать Vector<Vector<T>(nrows)>(ncols)
, но это то, что мне нужно!
Возможное решение будет в том числе размер внутри шаблона:
template <typename T, size_t N>
class Vector
{
public:
Vector() {
elements = new T[N];
}
/* Here more stuff, like operator[] etc... */
private:
T * elements;
}
Поэтому я бы больше не нужны параметры конструктора, но это также заставляет меня писать неуклюжий код с шаблонами везде (по exmample, каждая функция, используя Vector
должен быть объявлен как
template <typename T, size_t N>
void foo (Vector<T,N> &vec) {...}
у вас есть лучшие решения?
EDIT:
В качестве решения я черпал вдохновение из сообщений мистера Фуза и чумсада. Вот как я исправил проблему:
/* 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;
};
Спасибо большое всем!
Почему 'foo'« неуклюжий »? Даже без параметра N он все равно будет шаблонизирован. –
И значение 'size_t N', и время выполнения' dim' для решения различных проблем. Если размер является постоянным и известен во время компиляции, вы должны * использовать метод 'size_t N', потому что он использует проверку типов. Возможное переполнение где-то затем диагностируется в compiletime. В этом случае также нет необходимости в 'new' вообще - просто поместите обычный массив внутри, например' boost :: array '. –
@ jon hanson: да, но типы гораздо более общие, чем значения, поэтому определяющие 'foo (Vector &vec);' лучше, чем 'foo (Vector &vec);'. Для второго я предпочел бы определять foo как функцию шаблона. –
Dacav