Jump to content
  • Advertisement
Sign in to follow this  
Misery

Overload comma , operator to init the array

This topic is 2181 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hello,

I would like to overload comma , operator so it would be able to init the array.
The array is in the class:

template <class DataType,class IntType>
class Matrix
{
public:
DataType *Elements;
IntType Rows, Cols;
//some other functions and operators
};


How do I achieve the functionality lik in the blitz++ library, that allows to use such syntax:

Matrix<float,int> M;
M.Resize(2,2);
M=1, 0,
0, 1;


I have read some tutorials on internet and posts on gamedev and stackoverflow but I havent found what I was really looking for. Also tried to find implementation in blitz++ of this feature but without success.

Any help or suggestions would be appreciated,
Thanks in advance Edited by Misery

Share this post


Link to post
Share on other sites
Advertisement
Who cares if he overloads the , operator anyway? Its not like he is going to be doing anything useful for the next few years, given his choice of language.

As an empiricist, I say let him do it and learn the consequences for himself.

Share this post


Link to post
Share on other sites
Actually the initializer list solves the whole problem very well. But just one more question.
How do I make a constructor that could build the matrix using syntax like that (assuming that one can write here any number of rows):

M={
{1,2,3} //row 1
{4,5,6} //row 2
{7,8,9} //row 3
};

That is a problem because matrix defined in such manner can have any number of arguments (rows). How do I make that working? Should I use a variadic template?

Share this post


Link to post
Share on other sites

Actually the initializer list solves the whole problem very well. But just one more question.
How do I make a constructor that could build the matrix using syntax like that (assuming that one can write here any number of rows):

M={
{1,2,3} //row 1
{4,5,6} //row 2
{7,8,9} //row 3
};

That is a problem because matrix defined in such manner can have any number of arguments (rows). How do I make that working? Should I use a variadic template?


Unfortunately, this is not as clean:
https://groups.googl...1d7802958427622

However, you may consider supplying the arguments similarly to what you had in mind in your [font=courier new,courier,monospace]operator,[/font] solution:
M={
1,2,3, //row 1
4,5,6, //row 2
7,8,9 //row 3
}; Edited by Matt-D

Share this post


Link to post
Share on other sites
@Matt-D: That of course is a solution (and a good one really). But absolutely beautiful it would be if I could use the syntax with lists in the list.
Actually I have created a template variadic constructor, and it works. However there is only one more thing: how can I find out the number of arguments (rows) given so I could allocate the *Data?

template <class ... Args>
Matrix(Args ... args)
{
//do stuff
}


When I use a code like the one given with "rows", it calls this constructor. If I could somehow estimate the number of rows, I wouldn't need to call Alloc before using the lists.

Share this post


Link to post
Share on other sites
You could also create a temporary and hidden struct just for initialization, if you really want that syntax.

Something like this:

template <typename Type>
class MyMatrixRow
{
public:
MyMatrixRow(Type column1, Type column2, Type column3) :
column1(column1), column2(column2), column3(column3) { }

Type column1, column2, column3;
};

template <typename Type>
class MyMatrix
{
public:
MyMatrixRow(MyMatrixRow<Type> row1, MyMatrixRow<Type> row2, MyMatrixRow<Type> row3)
{
data.resize(9);

data[0] = row1.column1;
data[1] = row1.column2;
data[2] = row1.column3;

data[3] = row2.column1;
data[4] = row2.column2;
data[5] = row2.column3;

data[6] = row3.column1;
data[7] = row3.column2;
data[8] = row3.column3;
}

private:
std::vector<Type> data;
};


The structs passed in to the constructor are just used for constructing and then discarded.

The code:
MyMatrix<float> matrix = {{0.0f, 0.0f, 0.0f},
{0.0f, 0.0f, 0.0f},
{0.0f, 0.0f, 0.0f}};


Actually turns into:
MyMatrix<float> matrix(MyMatrixRow<float>(0.0f, 0.0f, 0.0f),
MyMatrixRow<float>(0.0f, 0.0f, 0.0f),
MyMatrixRow<float>(0.0f, 0.0f, 0.0f));


...and hopefully the entire MyMatrixRow() thing would be compiled out, but I don't know anything about compiler optimizing so I can't say for sure. Edited by Servant of the Lord

Share this post


Link to post
Share on other sites
OMG why doesn't initializer_list constructors work in VS2010?? sad.png
On Linux GCC it works just fine :|

EDIT: it doesn't support this functionality so I have to cancel it at the moment, as my project has to be portable. Pity.

Anyway thanks for help very much. Edited by Misery

Share this post


Link to post
Share on other sites
Thanks to (Servant of the Lord)'s idea I've managed to do a syntax that works exactly as I wanted, and - at least to me (but I'm not an experienced programmer) - seems quite effective. To get even nicer, this solution cannot be used in VC++ but, it doesn't collide with it (maybe someday they will support init lists, as they have appropriate headers and stuff). So this initializer constructor can be defined, but cannot be used in VC++, but works with compiers that support this feature. I have tested it in Ubuntu Linux 12.04 with its default GCC compiler suite. I'm just putting it here if someone would search for such snippet.

Thanks Gyus for Your time! And special thanks for suggestions not to overload comma operator. :]

The row class:

template<class DATA_TYPE,class INT_TYPE>
class Row
{
public:
Row()
{ }
Row(const initializer_list<DATA_TYPE> &list) : L(list)
{ }
DATA_TYPE operator [](INT_TYPE i) const
{
return *(L.begin()+i);
}
INT_TYPE Size() const
{
return L.size();
}
private:
const initializer_list<DATA_TYPE> &L;
};


Matrix class:

template<class DATA_TYPE,class INT_TYPE>
class Matrix
{
public:
DATA_TYPE *Data;
INT_TYPE Rows,Cols;
Matrix()
{
cout<<"basic ctr"<<endl;
Data=NULL;
Rows=0;
Cols=0;
}
Matrix(initializer_list<DATA_TYPE> RowVec) //initializer for M={1,2,3,...,N}
{
Data=NULL;
Rows=0;
Cols=0;
Cols=RowVec.size();
if (Cols==0) Free();
else
{
Alloc(1,Cols);
INT_TYPE k=0;
typename initializer_list<DATA_TYPE >::iterator i=RowVec.begin();
for (i=RowVec.begin();i!=RowVec.end();i++) Data[k++]=*i;
}
}
Matrix(initializer_list<Row<DATA_TYPE,INT_TYPE> > RowsL) //initializer for M= { {}, {}, {}}
{
Data=NULL;
Rows=0;
Cols=0;
Rows=RowsL.size();
if (Rows==0) Free();
else
{
INT_TYPE k=0;
typename initializer_list<Row<DATA_TYPE,INT_TYPE> >::iterator i=RowsL.begin();
Cols=(*i).Size();
Alloc(Rows,Cols);
for (i=RowsL.begin();i!=RowsL.end();i++)
{
if (Cols!=(*i).Size()) { Free(); /* throw an error: inconsistient row/colums dimensions*/cout<<"Err: ircd"<<Cols<<endl;}
else
{
for (int j=0;j<(*i).Size();j++)
{
Data[j*Rows+k]=(*i)[j];
}
}
k++;
}
}
}
void Alloc(INT_TYPE R,INT_TYPE C)
{
Free();
Data=new DATA_TYPE[R*C];
Rows=R;
Cols=C;
}
void Free()
{
delete[] Data;
Data=NULL;
Rows=0;
Cols=0;
}
};


And now it is possible to use initialzier lists, in similar way as it is in Mathematica. So it is possible to init any rectangular array in a nice looking and intuitive fashion, for example:

Matrix<float,int> M,E,r,c;
M={
{0,1,0},
{0,0,0},
};

E={
{1,0,0},
{0,1,0},
{0,0,1}
};

r={3,2,1};
c={
{1},
{2},
{3},
{4}
}


Regards smile.png

PS.: #include <initializer_list> Edited by Misery

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!