• Create Account

Overload comma , operator to init the array

Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

17 replies to this topic

#1Misery  Members   -  Reputation: 247

Like
0Likes
Like

Posted 27 July 2012 - 08:41 AM

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,

Edited by Misery, 27 July 2012 - 08:43 AM.

#2Servant of the Lord  Crossbones+   -  Reputation: 14369

Like
5Likes
Like

Posted 27 July 2012 - 10:06 AM

Overloading the comma operator for that usage is considered evil. Anytime you overload an operator for a usage that departs from what is normal, you create potential confusion for users using your code. Adding to the evilness, commas are used multiple places in C++ for multiple different purposes (unlike other operators)... but only one usage of the comma overloadable, and has lower priority than the others, which may lead to more confusion from time to time.

A much better initialization would be the more common, and thus more socially (among programmers) acceptable:
m = {1, 0, 0, 1};

However, if you want to go ahead and do it anyway, here's how:
MyClass &MyClass::operator ,(int value)
{
//...do whatever with 'value'.

return *this; //Return a reference to myself.
}

You overload the operator, handle the (one!) parameter, then you return a reference to yourself for the next operator to work on.
myClass , a, b, c, d

Is parsed as:
((((myClass , a) , b) , c) , d)

...as the return value is a reference to yourself to call the next operator.

If you want to use the more preferable way:
//Initialize:
MyClass m = {1, 0, 0, 1};

//Or assign later:
m = {0, 2, 11, 17};

...you can do so through the new C++11's standard std::initializer_list<>, if you are using an up-to-date compiler with C++11 enabled. This is what the standard library does now.

Edited by Servant of the Lord, 27 July 2012 - 11:12 AM.

It's perfectly fine to abbreviate my username to 'Servant' rather than copy+pasting it all the time.

All glory be to the Man at the right hand... On David's throne the King will reign, and the Government will rest upon His shoulders. All the earth will see the salvation of God.                                                                                                                                                       [Need free cloud storage? I personally like DropBox]

#3Álvaro  Crossbones+   -  Reputation: 9881

Like
7Likes
Like

Posted 27 July 2012 - 01:18 PM

Please, do not overload operators that people don't expect to be overloaded. Overloading operators like ",", "&&" and "||" is particularly evil because their evaluation properties (look up sequence points and short-circuit evaluation) change whether they are overwritten or not, so the potential for obfuscation is enormous.

Edited by alvaro, 27 July 2012 - 01:18 PM.

#4speciesUnknown  Members   -  Reputation: 527

Like
-15Likes
Like

Posted 27 July 2012 - 02:02 PM

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.
Don't thank me, thank the moon's gravitation pull! Post in My Journal and help me to not procrastinate!

#5Misery  Members   -  Reputation: 247

Like
0Likes
Like

Posted 27 July 2012 - 02:49 PM

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?

#6Matt-D  Crossbones+   -  Reputation: 1395

Like
1Likes
Like

Posted 27 July 2012 - 03:01 PM

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 operator, solution:
M={
1,2,3, //row 1
4,5,6, //row 2
7,8,9 //row 3
};

Edited by Matt-D, 27 July 2012 - 03:03 PM.

#7Misery  Members   -  Reputation: 247

Like
0Likes
Like

Posted 27 July 2012 - 03:25 PM

@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.

#8Servant of the Lord  Crossbones+   -  Reputation: 14369

Like
3Likes
Like

Posted 27 July 2012 - 03:34 PM

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, 27 July 2012 - 03:36 PM.

It's perfectly fine to abbreviate my username to 'Servant' rather than copy+pasting it all the time.

All glory be to the Man at the right hand... On David's throne the King will reign, and the Government will rest upon His shoulders. All the earth will see the salvation of God.                                                                                                                                                       [Need free cloud storage? I personally like DropBox]

#9Misery  Members   -  Reputation: 247

Like
0Likes
Like

Posted 27 July 2012 - 04:13 PM

OMG why doesn't initializer_list constructors work in VS2010??
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, 27 July 2012 - 04:23 PM.

#10Misery  Members   -  Reputation: 247

Like
1Likes
Like

Posted 28 July 2012 - 02:01 AM

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

PS.: #include <initializer_list>

Edited by Misery, 28 July 2012 - 02:05 AM.

#11Aardvajk  Crossbones+   -  Reputation: 3387

Like
3Likes
Like

Posted 28 July 2012 - 02:29 AM

Seriously now, why are you needing to frequently initialise matrices with lists of constants?

Would it not be clearer to have stuff like:

Matrix identityMatrix();
Matrix rotationZMatrix(float angle);


and just do whatever is easiest to implement inside these relatively few functions?

Be far more clear reading code that uses named methods to construct matrices than wading through code containing any of the above, no matter how the detail of the initialisation syntax happens to be expressed.

#12Misery  Members   -  Reputation: 247

Like
1Likes
Like

Posted 28 July 2012 - 03:01 AM

@Aardvajik:
Hello,
I am a scientist in CFD. I was asked to create a "friendly" library for scientific computations. I know, there are many of those, but none of them fulfills all of these criteria at once:
- includes matrix classes, sparse matrix classes, graphs, FEM meshes, solvers (I know, I know, Dune does for example) under one common interface
- is intuitive for people using Scilab, Matlab, Octave, Mathematica etc (this is why I aim to create such syntax)
- has easy to use installer on both Windows and Linux
- is portable between Windows/Linux and Intel C++, VS C++ and GCC on those platforms
- is written in compiled language, so it is much faster than scientific script languages, and avoids copying of arrays (what is common in Scilab for example)
- to use: include only one header and done, no needed fortran to C and C to C++ etc compilations, using Linux to windows cross compilers and so on

And to give You straight answer: Engineers and scientists very often use Mathematica, Matlab and silimar things.
And quite often we begin to learn programming using these (btw great) packages. And these script languages are oriented for using matrices, the same way as it is in engineering practice. We are used to init matrices "by hand". However, as one develops oneself tries to count more and more complicated things. And at some moment those scientific packages seem too slow, even to use them at super computers (on our HPC Task server, if Your computations are not finished in a week, they are canceled).

So what I am trying to do is to create intuitive library, which can be easily installed and used by non-proffesional programmers (like myself).So they could easily count much larger cases than before.

I am guessing that You are a pro programmer. So Your viewpoint to this matter is quite different than someones who is just trying to do different job, but needs to create program to count anything. For You it is not a problem to choose a language, dependently to what You need to achieve. You need a good parsing - take Python, You need fast numerical algorithms - take C++ or Fortran. Need administrative scripts: take PowerShell or Perl...
But we - non-profesionals - don't look at those matters this way. Our job demands from us bit different things, and we are not (unfortunately) paid for spending time on learing new programming language.

You would be surprised how little most just-programming-users enigneers know about programming.

Edited by Misery, 28 July 2012 - 03:03 AM.

#13Aardvajk  Crossbones+   -  Reputation: 3387

Like
0Likes
Like

Posted 28 July 2012 - 12:54 PM

Fair enough

#14Matt-D  Crossbones+   -  Reputation: 1395

Like
1Likes
Like

Posted 28 July 2012 - 08:37 PM

@Aardvajik:
Hello,
I am a scientist in CFD. I was asked to create a "friendly" library for scientific computations. I know, there are many of those, but none of them fulfills all of these criteria at once:
- includes matrix classes, sparse matrix classes, graphs, FEM meshes, solvers (I know, I know, Dune does for example) under one common interface
- is intuitive for people using Scilab, Matlab, Octave, Mathematica etc (this is why I aim to create such syntax)
- has easy to use installer on both Windows and Linux
- is portable between Windows/Linux and Intel C++, VS C++ and GCC on those platforms
- is written in compiled language, so it is much faster than scientific script languages, and avoids copying of arrays (what is common in Scilab for example)
- to use: include only one header and done, no needed fortran to C and C to C++ etc compilations, using Linux to windows cross compilers and so on

Hey, have you considered looking into Eigen, http://eigen.tuxfamily.org/dox-devel/ ?
I think that it fulfills most of your requirements, other than some of the first one and the last one (I think, I usually just include what I need, but this one is trivial to solve if you prepare a header that would include everything -- not that I think it's a good practice, btw) -- but relatively speaking, since writing from the scratch seems to be your alternative anyway, wouldn't it be faster to build on Eigen as a foundation (and if you contribute your addons to an open-source project you'll get other benefits, like more eyes to catch more bugs, etc.),

#15Misery  Members   -  Reputation: 247

Like
0Likes
Like

Posted 29 July 2012 - 03:41 AM

@Matt-D:
Thank You for this suggestion. The lib seems quite interesting. I'm sure I will take a look at sources of Eigen, especially iterative solvers - that's what I was missing. But still this is matrix only package (and few more classes: plynomial for example) and I need to have a basic engineering lib that contains a bit more.
Maybe I should add a few more words of explanation:

I decided to create my own library that will be similar in usage to Scilab and/or Mathematica. So in general it will be some kind of code-compiled matrix operator. I am not trying to do everything from scratch, because probably my life wouldn't be long enough to make a good quality lib (creating a good sparse solver or mesh generator are another branches of sciences themselves). I am trying to make a reasonably fast and convenient common, homogenous interface to few well known and portable libraries. And this interface is my main job at the moment.
I will integrate (or already have integrated some of those libs/programs):
-CBLAS and CLAPCK,
-CGAL, GMSH, provide GiD mesh generator interface,
-Umfpack, SuperLU for sparse matrices.
-Intel MKL and AMD MKL support
And some more... maybe Boost.units? Time will show. For now I needed a realistic goal to achieve. In future I plan to integrate VTK and make python bindings.
I will add many of functions written by myself "copying" the functionality known from Scilab and Mathematica. Interpolation, differentation, integration and so on...
And if this lib become successful among my friends at work, and my students I will be happy to make it open-source (in the meaning that it will be well documented for developers and users, and tested and ready to download), as most of those libs are GPL licensed.

And why I will not use Eigen as a foundation? First if all: it is too late now to change the abosule basis. Second I want to have as much control over this project as possible. Third: I love programming and it gives me much fun.

Regards

#16Matt-D  Crossbones+   -  Reputation: 1395

Like
0Likes
Like

Posted 29 July 2012 - 10:32 AM

OK, fair enough :-)

#17jwezorek  Crossbones+   -  Reputation: 1596

Like
1Likes
Like

Posted 30 July 2012 - 04:51 PM

Engineers and scientists very often use Mathematica, Matlab and silimar things.
And quite often we begin to learn programming using these (btw great) packages. And these script languages are oriented for using matrices, the same way as it is in engineering practice. We are used to init matrices "by hand". However, as one develops oneself tries to count more and more complicated things. And at some moment those scientific packages seem too slow, even to use them at super computers (on our HPC Task server, if Your computations are not finished in a week, they are canceled).

But at this point -- when something like MatLab becomes too slow -- I think a better approach than switching to an entirely new language with an entirely new library, etc., is to stick with the original engineering environment but write extensions to it in C++ using the API exposed by its developer. In the case of MatLab MathWorks gives you the whole MEX interface and, I think, even has a MEX Compiler built into Matlab, so what you can do is profile your Matlab computations and re-write the slow parts in C++ interfacing via MEX. Anyway, that's what we did at my last job and it worked pretty well.

Not sure if Mathematica has something like this, but I'd actually be pretty surprised if it didn't

Edited by jwezorek, 30 July 2012 - 04:52 PM.

#18Misery  Members   -  Reputation: 247

Like
0Likes
Like

Posted 31 July 2012 - 08:48 AM

@jwezorek:
That's true, but when taking into concern Matlab or Mathematica the cost of those is very high. Especially Mathworks strategy is painful: You have to pay about \$470 for each component. For deployment tool, for compiler... Why not use free tools? Or just make a GPL code that will work on most compilers.
And still those Mathematica and Matlab libraries are distributed as dll's (or so). How would anybody move such application to different platform. Let's say to platform with Itanium processors?

Matlab and Mathematica are really great tools, but it is for a reason why I decided tf rsuch solution.

Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

PARTNERS