Nested templates and constructor - c++

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!

In OO terms, I would vote for "has" a relationship between Matrix and a Vector. A Matrix has vectors, rather than a Matrix "is a" vector, which means that Matrix should not derive from Vector.
EDIT 1: A small correction. "..which means that Matrix should not derive "publicly" from Vector". Private inheritance may be still fine.

Use placement-new like this (burried behind the uninitialized_fill call)
template <typename T>
class Vector
{
public:
Vector(size_t dim, T const& c = T()) {
dimension = dim;
elements =
static_cast<T*>(operator new(sizeof(T) * dim));
std::uninitialized_fill(elements, elements + dim, c);
}
/* Here more stuff, like operator[] etc... */
private:
size_t dimension;
T * elements;
};
Then you can call the constructor with Matrix::Vector(ncols, Vector<T>(nrows)) (you don't need to repeat the argument for the outer Vector, because Vector refers to Vector< Vector<T> > automatically since you inherit from the outer Vector. You need to make sure to call destructors manually before doing operator delete(elements) in the destructor then.
You might also want to embed the vector as a member, which i would probably prefer because I imagine not necessarily all operations of the outer vector make sense for a matrix. Then the initialization looks like m(ncols, Vector<T>(nrows)).
It should be noted that std::vector can also be used for this
template <typename T>
class Vector
{
public:
Vector(size_t dim, T const& c = T()):elements(dim, c)
{ }
private:
std::vector<T> elements;
};
This is an easy and safe way to accomplish that, and you get automatic memory management.

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.

It depends on what you expect from your Vector (and Matrix) class.
Either you want the size to be determined at runtime, and in that case, I'd suggest adding a resize() function which would allow you to size the Vector in the constructor as you like.
template <typename T>
class Vector
{
public:
Vector(size_t dim) {
dimension = dim;
elements = new T[dim];
}
Vector() : dimension(0), elements(0) {} // you need default constructor
void resize(size_t dim) { // note: this could be implemented a lot better
T* new_elements=new T[dim];
for(int i=0; i<dim && i<dimension; i++)
new_elements[i]=elements[i];
delete [] elements;
elements=new_elements; dimension=dim;
}
/* Here more stuff, like operator[] etc... */
private:
size_t dimension;
T * elements;
}
You would then resize your Vectors in the Matrix constructor in a loop.
If you want the size of your vector or matrix to be determined at compile time, the best thing probably would be to use the template non-type argument as you suggested.

Related

Initializing an std::array with an std::intializer_list passed as a parameter

I am implementing a Matrix class in C++ and I want to be able to initialize it with an intializer list like so:
Matrix<double, 2, 3> m({{1,2,1},
{0,1,1}});
In the class I have implemented the constructor like this:
template<typename Ty, unsigned int rows, unsigned int cols>
class Matrix
{
std::array<std::array<Ty, cols>, rows> data;
public:
Matrix(const std::initializer_list<std::initializer_list<Ty>>& list)
{
int i = 0;
for (auto& list_row : list)
{
int j = 0;
for (auto& list_value : list_row)
{
data[i][j++] = list_value;
}
i++;
}
}
}
The code work but I have a couple of questions. Is it possible to make it safe, so it only takes initializer lists of a certain size(the size of the matrix) and secondly can I make the code more concise - I had imagined something like this:
Matrix(const std::initializer_list<std::initializer_list<Ty>>& list)
: data(list)
{ }
And it doesn't work but any better way to do it would be appreciated.
There's a pretty easy way to make it safe:
template<typename Ty, unsigned int rows, unsigned int cols>
class Matrix
{
std::array<std::array<Ty, cols>, rows> data;
public:
Matrix(std::array<std::array<Ty, cols>, rows> const& in)
: data(in)
{ }
};
This lets you almost use the syntax you want - you just need one extra set of {}s.
There's no way to statically enforce the size of a std::initializer_list - you'd have to assert or throw to prevent me from passing in a bunch of extra values and causing you to perform out-of-range writes.

Preset template argument for specific constructor

I am currently in the process of implementing a scientific toolkit using C++. When i implemented the Matrix class i encountered a problem with the conversion constructor:
template<size_t ROWS, size_t COLS = ROWS>
class Matrix {
public:
...
/** \brief Creates a matrix from a vector */
Matrix<ROWS, 1> (const Vector<ROWS>& vector) {
for (size_t i = 0; i < ROWS; i++) {
(*this)[i][0] = vector[i];
}
...
}
This code compiles just fine with clang++, but fails using g++ with
matrix.h:43:18: error: invalid declarator before ‘(’ token
Matrix<ROWS, 1> (const Vector<ROWS>& vector) {
Is there any other way to force certain template arguments for specific constructors? Is the way i am doing it not standard-compliant or should i report a bug to gcc?
Use partial specialization like this:
template<size_t ROWS, size_t COLS = ROWS>
class Matrix {
// ... (regular ROWS x COLS matrix code)
};
template<size_t ROWS>
class Matrix<ROWS, 1u> {
// ... (more ROWS x 1 matrix code)
/// \brief Creates a matrix from a vector
Matrix(const Vector<ROWS> & vector) {
for (size_t i = 0u; i < ROWS; i++)
(*this)[i][0u] = vector[i];
}
// ... (more ROWS x 1 matrix code)
};
Or if this would result in too much code duplication, just declare a common base class for the specializations. For example something like this (in c++11):
template<size_t ROWS, size_t COLS = ROWS>
class MatrixBase {
// ... (regular ROWS x COLS matrix code)
};
template<size_t ROWS, size_t COLS = ROWS>
class Matrix: public MatrixBase<ROWS, COLS> {
public: /* Methods: */
using MatrixBase<ROWS, COLS>::MatrixBase;
};
template<size_t ROWS>
class Matrix<ROWS, 1u>: public MatrixBase<ROWS, 1u> {
public: /* Methods: */
using MatrixBase<ROWS, 1u>::MatrixBase;
Matrix(const Vector<ROWS> & vector) {
for (size_t i = 0u; i < ROWS; i++)
(*this)[i][0u] = vector[i];
}
};
For C++03 and earlier you can't use the using keyword this way and may still have to define constructors for all specializations which call the respective base class constructors, e.g. Matrix(SomeArg arg) : MatrixBase(arg) {}. And if you're using GCC 4.7 where this C++11 using statement is not supported, you can use perfect forwarding to avoid writing separate constructors in the specializations for all base class constructors, e.g. template <typename ... Args> Matrix(Args && ... args) : MatrixBase(std::forward<Args>(args)...) {}.
Is it necessary to reimplement all methods, or is it somehow possible to use unspecialized methods in the specialized template without duplicating code?
A partially-specialized class doesn't contain declarations of the primary template's member functions, static member functions, enumerations, member classes, etc. Therefore you would have to redefine the entire class and reimplement them if you want to use them. As an alternative, if you have C++11 support, you can use constructor delegation by calling a private constructor based on a given condition:
template<size_t ROWS, size_t COLS = ROWS>
class Matrix
{
public:
Matrix(const Vector<ROWS>& vector)
: Matrix(vector, std::integral_constant<bool, COLS == 1>())
{ }
private:
// Implementation for COLS == 1
Matrix(const Vector<ROWS>& vector, std::true_type)
{
}
// Implementation for COLS != 1
Matrix(const Vector<ROWS>& vector, std::false_type)
{
}
};

Wrap existing memory with const std::vector?

OK, so I recently learned that (a) std::vector uses contiguous memory by definition/standard, and thus (b) &(v[0]) is the address of that contiguous block of memory, which you can read/write to as an old-skool C-array. Like...
void printem(size_t n, int* iary)
{ for (size_t i=0; i<n; ++i) std::cout << iary[i] << std::endl; }
void doublem(size_t n, int* iary)
{ for (size_t i=0; i<n; ++i) iary[i] *= 2; }
std::vector<int> v;
for (size_t i=0; i<100; ++i) v.push_back(i);
int* iptr = &(v[0]);
doublem(v.size(), iptr);
printem(v.size(), iptr);
OK, so that's cool, but I want to go in the other direction. I have lots and lots of existing code like
double computeSomething(const std::vector<SomeClass>& v) { ... }
If I have a C-array of objects, I can use such code like this:
SomeClass cary[100]; // 100*sizeof(SomeClass)
// populate this however
std::vector<SomeClass> v;
for (size_t i=0; i<100; ++i) v.push_back(cary[i]);
// now v is also using 100*sizeof(SomeClass)
double x = computeSomething(v);
I would like to do that (a) without the extra space and (b) without the extra time of inserting a redundant copy of all that data into the vector. Note that "just change your stupid computeSomething, idiot" is not sufficient, because there are thousands of such functions/methods that exhibit this pattern that are not under my control and, even if they were are too many to go and change all of them.
Note also that because I am only interested in const std::vector& usage, there is no worry that my original memory will ever need to be resized, or even modified. I would want something like a const std::vector constructor, but I don't know if the language even allows special constructors for const instances of a class, like:
namespace std { template <typename T> class vector {
vector() { ... }
vector(size_t n) { ... }
vector(size_t n, const T& t) { ... }
const vector(size_t n, T*) { ... } // can this be done?
...
If that is not possible, how about a container derived off of std::vector called std::const_vector, which (a) could construct from a pointer to a c-array and a size, and (b) purposefully did not implement non-const methods (push_back, resize, etc.), so then even if the object with a typename of const_vector is not actually a const object, the interface which only offers const methods makes it practically const (and any erroneous attempts to modify would be caught at compile time)?
UPDATE: A little messing around shows that this "solves" my problem wrt Windows-implementation of std::vector:
template <typename T>
class vector_tweaker : public std::vector<T> {
public:
vector_tweaker(size_t n, T* t) {
_saveMyfirst = _Myfirst;
_saveMylast = _Mylast;
_saveMyend = _Myend;
_Myfirst = t;
_Mylast = t + n;
_Myend = t + n;
}
~vector_tweaker() {
_Myfirst = _saveMyfirst;
_Mylast = _saveMylast;
_Myend = _saveMyend; // and proceed to std::vector destructor
}
private:
T* _saveMyfirst;
T* _saveMylast;
T* _saveMyend;
};
But of course that "solution" is hideous because (a) it offers no protection against the base class deleting the original memory by doing a resize() or push_back() (except for a careful user that only constructs const vector_tweaker()) -- and (b) it is specific to a particular implementation of std::vector, and would have to be reimplemented for others -- if indeed other platforms only declare their std::vector member data as protected: as microsoft did (seems a Bad Idea).
You can try reference-logic storing introduced in C++11 with std::reference_wrapper<>:
SomeClass cary[100];
// ...
std::vector<std::reference_wrapper<SomeClass>> cv;
cv.push_back(cary[i]); // no object copying is done, reference wrapper is stored
Or without C11, you can create a specialization of such template class for bytes - char. Then for the constructor from char* C-array you can use ::memcpy: which unfortunately will then use twice as much memory.
::memcpy(&v[0], c_arr, n);
Something like this:
template <typename T> class MyVector : public std::vector<T> {
};
template <> class MyVector<char> : public std::vector<char> {
public:
MyVector<char>(char* carr, size_t n) : std::vector<char>(n) {
::memcpy(&operator[](0), carr, n);
}
};
What I would recommend - replace all C-arrays to vectors where possible, then no extra copying will be needed.

Deleting templated C++ 2-dimensional array

Annoyance over C++'s requirement to pass a dimension in a 2-d array got me working on a templated Matrix class. I've been coding in C# for a bit, so I'm sure I'm a little rusty here.
Issue is, I get a heap exception as soon as I hit the destructor, which is trying to delete the 2-d array.
Any help gratefully accepted!
template <typename T>
class Matrix {
public:
Matrix(int m, int n) : nRows(m), nCols(n) {
pMatrix = new T * [nRows];
for (int i = 0; i < nCols; i++) {
pMatrix[i] = new T[nCols];
}
}
~Matrix() {
if (pMatrix != NULL) {
for (int i = 0; i < nRows; i++) { delete[] pMatrix[i]; }
delete[] pMatrix;
}
}
T ** GetMatrix() const { return pMatrix; }
T * Row(int i) const { return pMatrix[i]; }
inline T Cell(int row, int col) const { return pMatrix[row][col]; }
inline int GetNRows() const { return nRows; }
inline int GetNCols() const { return nCols; }
private:
int nRows, nCols;
T ** pMatrix;
};
This is the bug:
for (int i = 0; i < nCols; i++) {
pMatrix[i] = new T[nCols];
}
The loop should be until nRows, not nCols.
Other than that, let me tell you about something I did when I got tired of allocating 2-d arrays. I had to do a 3-d array. I used a map, that mapped from a coordinate - a struct holding x, y, z to the type I wanted.
I worked fast, and no need to allocate or deallocate. Assigning to a coordinate was simply done by
mymap[Coord(x, y, z)] = whatever...
Of course I needed to define the Coord struct and overload the < operator, but I found that way more comvenient than trying to allocate and deallocate a 3-d array.
Of course you will need to check if this scheme is fast enough for you. I used it to draw cells within a big cube using OpenGL and had no complaints at all.
Concerning the bug, #CodeChords_man explained it right. I have notes on implementation. I recommend to look through this wonderful FAQ post.
You should not use dynamic memory allocation unless you are 100% sure that
You really need it
You know how to implement it
I don't know of the first, and how the performance is crucial for you. But as for the second, you at least violated the rule of three. You class is very unsafe to use. If you copy it, the memory buffer will then be double-deleted.
You should not afraid to used STL containers, they are fast and optimized. At least the std::vector, it is as fast as the raw pointer in many scenarios. You can rewrite you class using std::vector as follows:
template <typename T>
class Matrix {
public:
typedef std::vector<T> MatrixRow;
typedef std::vector<MatrixRow> MatrixBody;
Matrix(int m, int n) : nRows(m), nCols(n), _body(m, MatrixRow(n)) {}
const MatrixBody& GetMatrix() const { return _body; }
const MatrixRow& GetRow(int i) const { return _body[i]; }
inline T Cell(int row, int col) const { return _body[row][col]; }
inline int GetNRows() const { return nRows; }
inline int GetNCols() const { return nCols; }
private:
int nRows, nCols;
MatrixBody _body;
};
Since this class is not using dynamic memory allocation, it is safe to copy and assign. You also don't need to explicitly store nRows and nCols in this case; you can use _body.size() and _body[0].size() instead.
Concerning underlying vector of vectors, it is dereferenced using the same [i][j] construction. It is easily iterated with begin() and end(). And if you absolutely need to use the raw pointer in some routine, you can always access it with &row[0].
The only possible difficulty is that you cannot easily convert MatrixBody to T**. But think it twice, maybe you don't really need to use T** at all.

C++: how to initialize the dimensions of a matrix inside a class through parameters of its constructor?

I need help in something really simple, which C++ makes very difficult. I created a class, lattice, with the aim to initialize and treat a matrix. There are the following private members:
private unsigned dim;
private double matrix [dim][dim];
I would like to initialize the variable dim in the constructor of the class through a parameter, but the compiler continue to return errors. I tried to make dim public and static and initializing it in the main program, but there are still problems. How could I create this simple class?
Moreover, I also implemented some methods in the class in order to update the values of the matrix. Is it true that, initializing an object of the class in a main program and then using its "updating" methods, the values of the matrix are stored only once?
Thank you for your help.
There are (at least) three ways to create such a class:
with a template
template<size_t dim>
class Matrix
{
private:
double matrix[dim][dim];
}
with the use of built in types such as std::vector (e.g. valarray would work too)
#include <vector>
class Matrix
{
private:
size_t dim;
std::vector<std::vector<double> > matrix;
public:
Matrix(size_t dim_) : dim(dim_), matrix()
{
matrix.resize(dim);
for ( size_t i = 0; i < dim; ++i )
matrix[i].resize(dim);
}
}
with the use of plain arrays (I do not recommend that!)
class Matrix
{
private:
size_t dim;
double** matrix;
public:
Matrix(size_t dim_) : dim(dim_), matrix()
{
matrix = new double*[dim];
for ( size_t i = 0; i < dim; ++i )
matrix[i] = new double[dim];
}
~Matrix() // you need a destructor!
{
for ( size_t i = 0; i < dim; ++i )
delete [] matrix[i];
delete [] matrix;
}
}
Use template:
template<int dim>
class Lattice{
double matrix[dim][dim];
}
and initialize dim in the constructor:
Lattice<10> sampleLattice;
Then dim = 10;
You might use pointer, or vector of a vector, but template is what I would use because it is less confusing and convenient.
BTW you will have to use private: and public: (with colon).
I'm guessing your "problems" are the compiler complaining about array initialization with non const size.
You should do something like this:
class MyClass {
public:
MyClass(unsigned pdim);
private:
MyClass();
const unsigned dim;
const double matrix [dim][dim];
};
MyClass::MyClass(unsigned pdim) : dim(pdim) {
// Other things
}
You can have const members inside a class but they need to be initialized using the : syntax.