I state that I am a C programmer more than a C++ programmer (with C++ I'm a beginner: p)
I've written a C++ class to manage multidimensional arrays (n-dimensional matrices). This class has methods to create the matrix and to set and to get value in/from the matrix (also to set the position inside it).
I've two issues:
With the idea that I want a syntax similar to m(x,y,z, ..., n) to set/get values some methods use the ellipsis E.G.: getValue(int dim0,...); But I think it's dangerous; although in the functions I've written I assume that the passed arguments are the same number of the matrix dimensions, the user might pass less values than necessary, then he will have no compiler errors or warnings.
I want to be able to manage the data type that the matrix cells contain during runtime at matrix creation time (without the use of union and somehow declaring the type). In the class code I've inserted a typedef (for development purposes) which indicates the points where such a modifications would/might impact.
For the first issue I've no ideas better than those implemented. Do you have suggestions?
To solve the second issue, I might think to create overloads for the methods getValue(), setValue() and createMatrix(), but this idea requires some workarounds and probably to rewrite completely each single method and then to have more copies of the "same" code (I want avoid that with the intent to have a better maintenance capability) , moreover this solution doesn't grant to manage all possible types. I'm thinking about the use of templates, but I don't understand if such a way is the better way. Do you have suggestions?
These are the main methods to be modified to solve both the issues:
methods in the CPP module:
int Matrix::createMatrix(Matrix::value_t *values)
{
int retval=1;
if ( (m_values!=NULL || !numOfDim()) && valAreIntAlloc()==true ) {
return 0;
}
if (values!=NULL) {
m_values=values;
setValAreIntAlloc(false);
} else {
setValAreIntAlloc(true);
// Compute the number of elements for
// the whole matrix
for(int i=0;i<numOfDim();i++) {
retval*=numOfElemInDim(i);
if (!retval) {
//Indicate that a dimension has a 0 value
//as numOfElemInDim! The caller will be allowed
//to know the such a dimension using: -retval-1;
retval=-(i+1);
break;
}
}
if (retval>0) {
m_values=new value_t[retval];
if (m_values!=NULL)
retval=0;
}
}
//Returns:
//1 if values is an external allocated memory,
//0 if nothing has been allocated or the
//m_values is already set as internal!
//elsewhere the number of allocated elements.
return retval;
}
void Matrix::setPositions(int dim0, ...)
{
va_list vl;
va_start(vl,dim0);
setPosition(0,dim0);
for (int i=1;i<numOfDim();i++)
setPosition(i,va_arg(vl,int));
va_end(vl);
}
Matrix::value_t Matrix::getValue(int dim0, ...)
{
va_list vl;
va_start(vl,dim0);
setPosition(0,dim0);
for (int i=1;i<numOfDim();i++)
setPosition(i,va_arg(vl,int));
va_end(vl);
return getValue();
}
void Matrix::setValue(Matrix::value_t value, int dim0, ...)
{
va_list vl;
va_start(vl,dim0);
setPosition(0,dim0);
for (int i=1;i<numOfDim();i++)
setPosition(i,va_arg(vl,int));
va_end(vl);
setValue(value);
}
methods inline in the Header file:
inline value_t getValue() { return m_values[posInValueVector()]; }
inline void setValue(value_t value) { m_values[posInValueVector()]=value; }
The methods setPosition(), setPositions() are used to set the coordinates of the matrix cell to be managed; the method posInValueVector() computes the index inside the vector (created by the method createMatrix) of the matrix cell using the coordinates.
Here al the code:
main.cpp
#include <iostream>
#include <cstdio>
#include "matrix.h"
using namespace std;
int main()
{
Matrix m(3);
m.setNumOfElemInDims(4,5,6);
m.createMatrix();
for(int i=0;i<m.numOfElemInDim(0);i++)
for(int j=0;j<m.numOfElemInDim(1);j++)
for(int k=0;k<m.numOfElemInDim(2);k++)
m.setValue(i*100+j*10+k,i,j,k); // matrix(i,j,k)=i*100+j*10+k
//printout the values of all matrix(i,j,k) cells
//I've used the printf because I find it very simple!
for(int i=0;i<m.numOfElemInDim(0);i++)
for(int j=0;j<m.numOfElemInDim(1);j++)
for(int k=0;k<m.numOfElemInDim(2);k++)
printf("(%d,%d,%d)=%03.0f\n",i,j,k,m.getValue(i,j,k));
}
matrix.h
#ifndef MATRIX_H
#define MATRIX_H
class Matrix
{
public:
typedef double value_t;
Matrix();
Matrix(int numOfDim, int *nelem=NULL);
~Matrix();
inline unsigned int numOfDim() const {return m_numOfDim;}
int setNumOfDim(int numOfDim, int *nelem=NULL);
inline int numOfElemInDim(int dim) const
{return (dim<numOfDim())?m_numOfElemInDim[dim]:-1; }
int setNumOfElemInDim(int dim, int nelem);
int setNumOfElemInDims(int el0, ...);
int createMatrix(value_t *values);
inline int createMatrix() { return createMatrix(NULL); }
inline bool valAreIntAlloc() const {return m_valAreIntAlloc;}
inline void setValAreIntAlloc(bool valAreIntAlloc)
{m_valAreIntAlloc = valAreIntAlloc;}
inline int position(int dim) const {return m_positions[dim];}
inline void setPosition(int dim,int value)
{m_positions[dim] = value;}
inline void setPositions(int *positions)
{for(int i=0;i<numOfDim();i++) setPosition(i,positions[i]);}
void setPositions(int dim0, ...);
inline value_t getValue() { return m_values[posInValueVector()]; }
value_t getValue(int dim0, ...);
inline void setValue(value_t value) { m_values[posInValueVector()]=value; }
void setValue(value_t value, int dim0, ...);
private:
int m_numOfDim;
int * m_numOfElemInDim;
int * m_positions;
value_t * m_values;
bool m_valAreIntAlloc;
int posInValueVector();
};
#endif // MATRIX_H
matrix.cpp
#include <iostream>
#include <cstdarg>
#include "matrix.h"
#define __INIT__(v)\
m_numOfDim(v),\
m_numOfElemInDim(NULL),\
m_positions(NULL),\
m_values(NULL),\
m_valAreIntAlloc(false)
Matrix::Matrix():
__INIT__(0)
{
}
Matrix::~Matrix()
{
if (m_numOfElemInDim!=NULL)
delete m_numOfElemInDim;
if (m_positions!=NULL)
delete m_positions;
if (valAreIntAlloc() && m_values!=NULL)
delete m_values;
}
Matrix::Matrix(int numOfDim, int *nelem):
__INIT__(numOfDim)
{
setNumOfDim(numOfDim,nelem);
}
int Matrix::setNumOfDim(int numOfDim, int *nelem)
{
int retval=0;
m_numOfDim = numOfDim;
m_numOfElemInDim = new int[numOfDim];
if (m_numOfElemInDim==NULL)
return 1;
m_positions = new int[numOfDim];
if (m_positions==NULL)
return 2;
for(int i=0;i<m_numOfDim;i++) {
if (setNumOfElemInDim(i,(nelem==NULL)?0:nelem[i])) {
retval=-1;
break;
}
setPosition(i,0);
}
return retval; //All ok!
}
int Matrix::setNumOfElemInDim(int dim,int nelem)
{
int retval=-1;
if (dim<numOfDim()) {
m_numOfElemInDim[dim] = nelem;
retval=0;
}
return retval;
}
int Matrix::setNumOfElemInDims(int el0, ...)
{
va_list vl;
va_start(vl,el0);
setNumOfElemInDim(0,el0);
for (int i=1;i<numOfDim();i++)
setNumOfElemInDim(i,va_arg(vl,int));
va_end(vl);
return 0;
}
int Matrix::createMatrix(Matrix::value_t *values)
{
int retval=1;
if ( (m_values!=NULL || !numOfDim()) && valAreIntAlloc()==true ) {
return 0;
}
if (values!=NULL) {
m_values=values;
setValAreIntAlloc(false);
} else {
setValAreIntAlloc(true);
// Compute the number of elements for
// the whole matrix
for(int i=0;i<numOfDim();i++) {
retval*=numOfElemInDim(i);
if (!retval) {
//Indicate that a dimension has a 0 value
//as numOfElemInDim! The caller will be allowed
//to know the such a dimension using: -retval-1;
retval=-(i+1);
break;
}
}
if (retval>0) {
m_values=new value_t[retval];
if (m_values!=NULL)
retval=0;
}
}
//Returns:
//1 if values is an external allocated memory,
//0 if nothing has been allocated or the
//m_values is already set as internal!
//elsewhere the number of allocated elements.
return retval;
}
void Matrix::setPositions(int dim0, ...)
{
va_list vl;
va_start(vl,dim0);
setPosition(0,dim0);
for (int i=1;i<numOfDim();i++)
setPosition(i,va_arg(vl,int));
va_end(vl);
}
Matrix::value_t Matrix::getValue(int dim0, ...)
{
va_list vl;
va_start(vl,dim0);
setPosition(0,dim0);
for (int i=1;i<numOfDim();i++)
setPosition(i,va_arg(vl,int));
va_end(vl);
return getValue();
}
void Matrix::setValue(Matrix::value_t value, int dim0, ...)
{
va_list vl;
va_start(vl,dim0);
setPosition(0,dim0);
for (int i=1;i<numOfDim();i++)
setPosition(i,va_arg(vl,int));
va_end(vl);
setValue(value);
}
int Matrix::posInValueVector()
{
int pos=position(0);
for(int i=1;i<numOfDim();i++)
pos=pos*numOfElemInDim(i)+position(i);
return pos;
}