一个class来管理多维数组!如何管理单元格中的不同数据类型?
A class to manage multidimensional array! How can I do to manage different data types in the cells?
我声明我是 C 程序员而不是 C++ 程序员(对于 C++ 我是初学者:p)
我写了一个C++ class来管理多维数组(n维矩阵)。此 class 具有创建矩阵以及设置和获取值的方法 in/from 矩阵(也可以设置其中的位置)。
我有两个问题:
我想要一个类似于 m(x,y,z, ..., n) 的语法来 set/get 一些方法使用省略号 EG 的想法:getValue( int dim0,...);但我认为这很危险;尽管在我编写的函数中我假设传递的参数与矩阵维数相同,但用户传递的值可能比必要的少,那么他将没有编译器错误或警告。
我希望能够在矩阵创建时管理矩阵单元格在运行时包含的数据类型(不使用联合并以某种方式声明类型)。在 class 代码中,我插入了一个 typedef(用于开发目的),它指示此类修改 would/might 影响的点。
对于第一期,我没有比实施的想法更好的想法了。你有什么建议吗?
为了解决第二个问题,我可能会考虑为方法 getValue()、setValue() 和 createMatrix() 创建重载,但这个想法需要一些变通方法,并且可能需要完全重写每个方法,然后让"same" 代码的更多副本(我想避免这种情况以具有更好的维护能力),而且此解决方案不授予管理所有可能类型的权限。我正在考虑使用模板,但我不明白这样的方式是否更好。你有什么建议吗?
这些是解决这两个问题的主要修改方法:
CPP 模块中的方法:
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);
}
头文件中的内联方法:
inline value_t getValue() { return m_values[posInValueVector()]; }
inline void setValue(value_t value) { m_values[posInValueVector()]=value; }
setPosition()、setPositions()方法用于设置要管理的矩阵单元格的坐标;方法 posInValueVector() 使用坐标计算矩阵单元的向量(由方法 createMatrix 创建)内的索引。
代码如下:
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;
}
我找到了解决方案,但我并不完全喜欢它!
我修改了 createMatrix()、getValue() 和 setValue() 方法,并插入了两个用省略号定义完成函数的方法。这个想法是使用模板。以下是我希望它们成为模板的定义:
#define __MATRIX_GETVALUE(C,T,val,dim0...) \
va_list vl; \
va_start(vl,dim0); \
C->setPositions(vl,dim0); va_end(vl);\
val = *((T *)(m_values)+posInValueVector())
#define __MATRIX_SETVALUE(C,T,val,dim0...) \
va_list vl; \
va_start(vl,dim0); \
C->setPositions(vl,dim0); va_end(vl);\
*((T *)(m_values)+posInValueVector())=val
修改后的代码如下:
main.cpp
#include <iostream>
#include <cstdio>
#include "matrix.h"
using namespace std;
int main()
{
Matrix m(3);
m.setNumOfCellForDims(4,5,6);
puts("-----------------> DBL m(i,j,k)=i*100+j*10+k+111 -------------------");
m.createMatrix(sizeof(double));
for(int i=0;i<m.numOfCellInDim(0);i++)
for(int j=0;j<m.numOfCellInDim(1);j++)
for(int k=0;k<m.numOfCellInDim(2);k++)
m.setValue((double)i*100+j*10+k+111,i,j,k); // matrix(i,j,k)=i*100+j*10+k
//printout the values of all matrix(i,j,k) cells
double valdbl;
for(int i=0;i<m.numOfCellInDim(0);i++)
for(int j=0;j<m.numOfCellInDim(1);j++)
for(int k=0;k<m.numOfCellInDim(2);k++)
printf("(%d,%d,%d)=%03.0f\n",i,j,k,m.getValue(valdbl,i,j,k));
puts("-----------------> INT m(i,j,k)=i*100+j*10+k+222 -------------------");
m.clearMatrix();
m.setNumOfDim(3);
m.setNumOfCellForDims(4,5,6);
m.createMatrix(sizeof(int));
for(int i=0;i<m.numOfCellInDim(0);i++)
for(int j=0;j<m.numOfCellInDim(1);j++)
for(int k=0;k<m.numOfCellInDim(2);k++)
m.setValue((int)(i*100+j*10+k+222),i,j,k); // matrix(i,j,k)=i*100+j*10+k
//printout the values of all matrix(i,j,k) cells
int valint;
for(int i=0;i<m.numOfCellInDim(0);i++)
for(int j=0;j<m.numOfCellInDim(1);j++)
for(int k=0;k<m.numOfCellInDim(2);k++)
printf("(%d,%d,%d)=%03d\n",i,j,k,m.getValue(valint,i,j,k));
}
matrix.h
#ifndef MATRIX_H
#define MATRIX_H
#include <cstdarg>
#include <cstring>
#define __MATRIX_GETVALUE(C,T,val,dim0...) \
va_list vl; \
va_start(vl,dim0); \
C->setPositions(vl,dim0); va_end(vl);\
val = *((T *)(m_values)+posInValueVector())
#define __MATRIX_SETVALUE(C,T,val,dim0...) \
va_list vl; \
va_start(vl,dim0); \
C->setPositions(vl,dim0); va_end(vl);\
*((T *)(m_values)+posInValueVector())=val
class Matrix
{
public:
Matrix();
Matrix(int numOfDim, int *ncell=NULL);
~Matrix();
void clearMatrix();
inline unsigned int numOfDim() const {return m_numOfDim;}
int setNumOfDim(int numOfDim, int *ncell=NULL);
inline int numOfCellInDim(int dim) const
{return (dim<numOfDim())?m_numOfCellInDim[dim]:-1; }
int setNumOfCellForDim(int dim, int ncell);
int setNumOfCellForDims(int el0, ...);
int createMatrix(int size, void *values);
inline int createMatrix(int size) { return createMatrix(size,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 void * getValue() { return (char *)m_values+posInValueVector(); }
inline double getValue(double &value)
{ return value=*(double *)(m_values)+posInValueVector(); }
inline int getValue(int &value)
{ return value=*(int *)(m_values)+posInValueVector(); }
//void * getValue(int dim0, ...);
inline double getValue(double &value, int dim0, ...) {
__MATRIX_GETVALUE(this,double,value,dim0);
return value;
}
inline int getValue(int &value, int dim0, ...) {
__MATRIX_GETVALUE(this,int,value,dim0);
return value;
}
inline void setValue(double value)
{ *((double *)(m_values)+posInValueVector())=value; }
inline void setValue(int value)
{ *((int *)(m_values)+posInValueVector())=value; }
inline void setValue(void *value, int size)
{ memcpy((char *)m_values+posInValueVector(),(char *)value,size); }
//void setValue(double value, int dim0, ...);
inline void setValue(double value, int dim0, ...) {
__MATRIX_SETVALUE(this,double,value,dim0);
}
inline void setValue(int value, int dim0, ...) {
__MATRIX_SETVALUE(this,int,value,dim0);
}
inline int cellSize() const {return m_cellSize;}
inline void setCellSize(int cellSize) {m_cellSize = cellSize;}
private:
int m_numOfDim;
int m_cellSize;
int * m_numOfCellInDim;
int * m_positions;
void * m_values;
bool m_valAreIntAlloc;
int posInValueVector();
#ifdef MATRIX_CPP
inline
#endif
int setPositions(va_list &vl, const int &dim0);
};
#endif // MATRIX_H
matrix.cpp
#define MATRIX_CPP
#include <iostream>
#include "matrix.h"
#define __INIT__(v)\
m_numOfDim(v),\
m_cellSize(0), \
m_numOfCellInDim(NULL),\
m_positions(NULL),\
m_values(NULL),\
m_valAreIntAlloc(false)
Matrix::Matrix():
__INIT__(0)
{
}
Matrix::~Matrix()
{
clearMatrix();
}
void Matrix::clearMatrix()
{
if (m_numOfCellInDim!=NULL)
delete m_numOfCellInDim;
m_numOfCellInDim=NULL;
if (m_positions!=NULL)
delete m_positions;
m_positions=NULL;
if (valAreIntAlloc() && m_values!=NULL)
delete (char *)m_values;
m_values=NULL;
}
Matrix::Matrix(int numOfDim, int *ncell):
__INIT__(numOfDim)
{
setNumOfDim(numOfDim,ncell);
}
int Matrix::setNumOfDim(int numOfDim, int *ncell)
{
int retval=0;
m_numOfDim = numOfDim;
m_numOfCellInDim = new int[numOfDim];
if (m_numOfCellInDim==NULL)
return 1;
m_positions = new int[numOfDim];
if (m_positions==NULL)
return 2;
for(int i=0;i<m_numOfDim;i++) {
if (setNumOfCellForDim(i,(ncell==NULL)?0:ncell[i])) {
retval=-1;
break;
}
setPosition(i,0);
}
return retval; //All ok!
}
int Matrix::setNumOfCellForDim(int dim,int ncell)
{
int retval=-1;
if (dim<numOfDim()) {
m_numOfCellInDim[dim] = ncell;
retval=0;
}
return retval;
}
int Matrix::setNumOfCellForDims(int el0, ...)
{
va_list vl;
va_start(vl,el0);
setNumOfCellForDim(0,el0);
for (int i=1;i<numOfDim();i++)
setNumOfCellForDim(i,va_arg(vl,int));
va_end(vl);
return 0;
}
int Matrix::createMatrix(int size, void *values)
{
int retval=1;
setCellSize(size);
if ( (m_values!=NULL || !numOfDim()) && valAreIntAlloc()==true ) {
return 0;
}
if (values!=NULL) {
m_values=values;
setValAreIntAlloc(false);
} else {
setValAreIntAlloc(true);
// Compute the number of cellents for
// the whole matrix
for(int i=0;i<numOfDim();i++) {
retval*=numOfCellInDim(i);
if (!retval) {
//Indicate that a dimension has a 0 value
//as numOfCellInDim! The caller will be allowed
//to know the such a dimension using: -retval-1;
retval=-(i+1);
break;
}
}
if (retval>0) {
m_values=new char[retval*cellSize()];
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 cellents.
return retval;
}
void Matrix::setPositions(int dim0, ...)
{
va_list vl;
va_start(vl,dim0);
setPositions(vl,dim0);
va_end(vl);
}
int Matrix::setPositions(va_list &vl,const int &dim0)
{
setPosition(0,dim0);
for (int i=1;i<numOfDim();i++)
setPosition(i,va_arg(vl,int));
}
int Matrix::posInValueVector()
{
int pos=position(0);
for(int i=1;i<numOfDim();i++)
pos=pos*numOfCellInDim(i)+position(i);
return pos;
}
我认为下面的解决方案,即 在另一个我的问题中,是一个漂亮的解决方案,实现了我想要的所有内容,但我使用了很多代码......它基于 C+ +11 个可变参数模板。
我对这段代码的一个怀疑是它管理内存的方式。我的意愿是内存是一个块,我几乎可以肯定这段代码不会那样做。然而是一个又好又快的代码!
template<typename T, int ...rest>
struct matrix;
template<typename T, int n>
struct matrix<T, n> {
T data[n];
matrix() {
for (int i=0; i<n; i++) {
data[i] = T(0);
}
}
T& operator[](int index) { return data[index]; }
};
template<typename T, int n, int ...rest>
struct matrix<T, n, rest...> {
matrix<T, rest...> data[n];
matrix<T, rest...>& operator[](int index) { return data[index]; }
};
可用于:
matrix<double, 10, 9, 4> m;
for (int i=0; i<10; i++) {
for (int j=0; j<9; j++) {
for (int k=0; k<4; k++) {
m[i][j][k] = i + j*2.718 + k*3.1416;
}
}
}
我声明我是 C 程序员而不是 C++ 程序员(对于 C++ 我是初学者:p)
我写了一个C++ class来管理多维数组(n维矩阵)。此 class 具有创建矩阵以及设置和获取值的方法 in/from 矩阵(也可以设置其中的位置)。
我有两个问题:
我想要一个类似于 m(x,y,z, ..., n) 的语法来 set/get 一些方法使用省略号 EG 的想法:getValue( int dim0,...);但我认为这很危险;尽管在我编写的函数中我假设传递的参数与矩阵维数相同,但用户传递的值可能比必要的少,那么他将没有编译器错误或警告。
我希望能够在矩阵创建时管理矩阵单元格在运行时包含的数据类型(不使用联合并以某种方式声明类型)。在 class 代码中,我插入了一个 typedef(用于开发目的),它指示此类修改 would/might 影响的点。
对于第一期,我没有比实施的想法更好的想法了。你有什么建议吗?
为了解决第二个问题,我可能会考虑为方法 getValue()、setValue() 和 createMatrix() 创建重载,但这个想法需要一些变通方法,并且可能需要完全重写每个方法,然后让"same" 代码的更多副本(我想避免这种情况以具有更好的维护能力),而且此解决方案不授予管理所有可能类型的权限。我正在考虑使用模板,但我不明白这样的方式是否更好。你有什么建议吗?
这些是解决这两个问题的主要修改方法:
CPP 模块中的方法:
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);
}
头文件中的内联方法:
inline value_t getValue() { return m_values[posInValueVector()]; }
inline void setValue(value_t value) { m_values[posInValueVector()]=value; }
setPosition()、setPositions()方法用于设置要管理的矩阵单元格的坐标;方法 posInValueVector() 使用坐标计算矩阵单元的向量(由方法 createMatrix 创建)内的索引。
代码如下:
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;
}
我找到了解决方案,但我并不完全喜欢它!
我修改了 createMatrix()、getValue() 和 setValue() 方法,并插入了两个用省略号定义完成函数的方法。这个想法是使用模板。以下是我希望它们成为模板的定义:
#define __MATRIX_GETVALUE(C,T,val,dim0...) \
va_list vl; \
va_start(vl,dim0); \
C->setPositions(vl,dim0); va_end(vl);\
val = *((T *)(m_values)+posInValueVector())
#define __MATRIX_SETVALUE(C,T,val,dim0...) \
va_list vl; \
va_start(vl,dim0); \
C->setPositions(vl,dim0); va_end(vl);\
*((T *)(m_values)+posInValueVector())=val
修改后的代码如下:
main.cpp
#include <iostream>
#include <cstdio>
#include "matrix.h"
using namespace std;
int main()
{
Matrix m(3);
m.setNumOfCellForDims(4,5,6);
puts("-----------------> DBL m(i,j,k)=i*100+j*10+k+111 -------------------");
m.createMatrix(sizeof(double));
for(int i=0;i<m.numOfCellInDim(0);i++)
for(int j=0;j<m.numOfCellInDim(1);j++)
for(int k=0;k<m.numOfCellInDim(2);k++)
m.setValue((double)i*100+j*10+k+111,i,j,k); // matrix(i,j,k)=i*100+j*10+k
//printout the values of all matrix(i,j,k) cells
double valdbl;
for(int i=0;i<m.numOfCellInDim(0);i++)
for(int j=0;j<m.numOfCellInDim(1);j++)
for(int k=0;k<m.numOfCellInDim(2);k++)
printf("(%d,%d,%d)=%03.0f\n",i,j,k,m.getValue(valdbl,i,j,k));
puts("-----------------> INT m(i,j,k)=i*100+j*10+k+222 -------------------");
m.clearMatrix();
m.setNumOfDim(3);
m.setNumOfCellForDims(4,5,6);
m.createMatrix(sizeof(int));
for(int i=0;i<m.numOfCellInDim(0);i++)
for(int j=0;j<m.numOfCellInDim(1);j++)
for(int k=0;k<m.numOfCellInDim(2);k++)
m.setValue((int)(i*100+j*10+k+222),i,j,k); // matrix(i,j,k)=i*100+j*10+k
//printout the values of all matrix(i,j,k) cells
int valint;
for(int i=0;i<m.numOfCellInDim(0);i++)
for(int j=0;j<m.numOfCellInDim(1);j++)
for(int k=0;k<m.numOfCellInDim(2);k++)
printf("(%d,%d,%d)=%03d\n",i,j,k,m.getValue(valint,i,j,k));
}
matrix.h
#ifndef MATRIX_H
#define MATRIX_H
#include <cstdarg>
#include <cstring>
#define __MATRIX_GETVALUE(C,T,val,dim0...) \
va_list vl; \
va_start(vl,dim0); \
C->setPositions(vl,dim0); va_end(vl);\
val = *((T *)(m_values)+posInValueVector())
#define __MATRIX_SETVALUE(C,T,val,dim0...) \
va_list vl; \
va_start(vl,dim0); \
C->setPositions(vl,dim0); va_end(vl);\
*((T *)(m_values)+posInValueVector())=val
class Matrix
{
public:
Matrix();
Matrix(int numOfDim, int *ncell=NULL);
~Matrix();
void clearMatrix();
inline unsigned int numOfDim() const {return m_numOfDim;}
int setNumOfDim(int numOfDim, int *ncell=NULL);
inline int numOfCellInDim(int dim) const
{return (dim<numOfDim())?m_numOfCellInDim[dim]:-1; }
int setNumOfCellForDim(int dim, int ncell);
int setNumOfCellForDims(int el0, ...);
int createMatrix(int size, void *values);
inline int createMatrix(int size) { return createMatrix(size,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 void * getValue() { return (char *)m_values+posInValueVector(); }
inline double getValue(double &value)
{ return value=*(double *)(m_values)+posInValueVector(); }
inline int getValue(int &value)
{ return value=*(int *)(m_values)+posInValueVector(); }
//void * getValue(int dim0, ...);
inline double getValue(double &value, int dim0, ...) {
__MATRIX_GETVALUE(this,double,value,dim0);
return value;
}
inline int getValue(int &value, int dim0, ...) {
__MATRIX_GETVALUE(this,int,value,dim0);
return value;
}
inline void setValue(double value)
{ *((double *)(m_values)+posInValueVector())=value; }
inline void setValue(int value)
{ *((int *)(m_values)+posInValueVector())=value; }
inline void setValue(void *value, int size)
{ memcpy((char *)m_values+posInValueVector(),(char *)value,size); }
//void setValue(double value, int dim0, ...);
inline void setValue(double value, int dim0, ...) {
__MATRIX_SETVALUE(this,double,value,dim0);
}
inline void setValue(int value, int dim0, ...) {
__MATRIX_SETVALUE(this,int,value,dim0);
}
inline int cellSize() const {return m_cellSize;}
inline void setCellSize(int cellSize) {m_cellSize = cellSize;}
private:
int m_numOfDim;
int m_cellSize;
int * m_numOfCellInDim;
int * m_positions;
void * m_values;
bool m_valAreIntAlloc;
int posInValueVector();
#ifdef MATRIX_CPP
inline
#endif
int setPositions(va_list &vl, const int &dim0);
};
#endif // MATRIX_H
matrix.cpp
#define MATRIX_CPP
#include <iostream>
#include "matrix.h"
#define __INIT__(v)\
m_numOfDim(v),\
m_cellSize(0), \
m_numOfCellInDim(NULL),\
m_positions(NULL),\
m_values(NULL),\
m_valAreIntAlloc(false)
Matrix::Matrix():
__INIT__(0)
{
}
Matrix::~Matrix()
{
clearMatrix();
}
void Matrix::clearMatrix()
{
if (m_numOfCellInDim!=NULL)
delete m_numOfCellInDim;
m_numOfCellInDim=NULL;
if (m_positions!=NULL)
delete m_positions;
m_positions=NULL;
if (valAreIntAlloc() && m_values!=NULL)
delete (char *)m_values;
m_values=NULL;
}
Matrix::Matrix(int numOfDim, int *ncell):
__INIT__(numOfDim)
{
setNumOfDim(numOfDim,ncell);
}
int Matrix::setNumOfDim(int numOfDim, int *ncell)
{
int retval=0;
m_numOfDim = numOfDim;
m_numOfCellInDim = new int[numOfDim];
if (m_numOfCellInDim==NULL)
return 1;
m_positions = new int[numOfDim];
if (m_positions==NULL)
return 2;
for(int i=0;i<m_numOfDim;i++) {
if (setNumOfCellForDim(i,(ncell==NULL)?0:ncell[i])) {
retval=-1;
break;
}
setPosition(i,0);
}
return retval; //All ok!
}
int Matrix::setNumOfCellForDim(int dim,int ncell)
{
int retval=-1;
if (dim<numOfDim()) {
m_numOfCellInDim[dim] = ncell;
retval=0;
}
return retval;
}
int Matrix::setNumOfCellForDims(int el0, ...)
{
va_list vl;
va_start(vl,el0);
setNumOfCellForDim(0,el0);
for (int i=1;i<numOfDim();i++)
setNumOfCellForDim(i,va_arg(vl,int));
va_end(vl);
return 0;
}
int Matrix::createMatrix(int size, void *values)
{
int retval=1;
setCellSize(size);
if ( (m_values!=NULL || !numOfDim()) && valAreIntAlloc()==true ) {
return 0;
}
if (values!=NULL) {
m_values=values;
setValAreIntAlloc(false);
} else {
setValAreIntAlloc(true);
// Compute the number of cellents for
// the whole matrix
for(int i=0;i<numOfDim();i++) {
retval*=numOfCellInDim(i);
if (!retval) {
//Indicate that a dimension has a 0 value
//as numOfCellInDim! The caller will be allowed
//to know the such a dimension using: -retval-1;
retval=-(i+1);
break;
}
}
if (retval>0) {
m_values=new char[retval*cellSize()];
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 cellents.
return retval;
}
void Matrix::setPositions(int dim0, ...)
{
va_list vl;
va_start(vl,dim0);
setPositions(vl,dim0);
va_end(vl);
}
int Matrix::setPositions(va_list &vl,const int &dim0)
{
setPosition(0,dim0);
for (int i=1;i<numOfDim();i++)
setPosition(i,va_arg(vl,int));
}
int Matrix::posInValueVector()
{
int pos=position(0);
for(int i=1;i<numOfDim();i++)
pos=pos*numOfCellInDim(i)+position(i);
return pos;
}
我认为下面的解决方案,即
我对这段代码的一个怀疑是它管理内存的方式。我的意愿是内存是一个块,我几乎可以肯定这段代码不会那样做。然而是一个又好又快的代码!
template<typename T, int ...rest>
struct matrix;
template<typename T, int n>
struct matrix<T, n> {
T data[n];
matrix() {
for (int i=0; i<n; i++) {
data[i] = T(0);
}
}
T& operator[](int index) { return data[index]; }
};
template<typename T, int n, int ...rest>
struct matrix<T, n, rest...> {
matrix<T, rest...> data[n];
matrix<T, rest...>& operator[](int index) { return data[index]; }
};
可用于:
matrix<double, 10, 9, 4> m;
for (int i=0; i<10; i++) {
for (int j=0; j<9; j++) {
for (int k=0; k<4; k++) {
m[i][j][k] = i + j*2.718 + k*3.1416;
}
}
}