ok so im not sure if its related to functors but from what i understood it is so
the question is:
lets assume i have the next class:
class Matrix{
public:
Matrix(int, int); // constructor
Matrix(const Matrix&); // copy constructor
Matrix& operator+= (const Matrix&);
Matrix& operator-= (const Matrix&);
int* operator[] (int) const;
private:
int rows;
int cols;
int** Mat_p;
};
and i want to overload the += and -= operators in Matrix class.
now, in order to sum or subtract 2 matrices we need to iterate over each value of both matrices and add or subtract so it will be some thing like:
Matrix& Matrix::operator+= (const Matrix& M){
for (int indexR = 0; indexR < rows; ++indexR)
for (int indexC = 0; indexC < cols; ++indexC)
Mat_p[indexR][indexC] += M[indexR][indexC];
}
Matrix& Matrix::operator-= (const Matrix& M){
for (int indexR = 0; indexR < rows; ++indexR)
for (int indexC = 0; indexC < cols; ++indexC)
Mat_p[indexR][indexC] -= M[indexR][indexC];
}
as you can see both operators "+=" and "-=" has the same structure give or take, so one of the basic so called "rules" is to avoid code duplication.
so the asked question is how do we avoid this duplication and keep the code effective ?
You could implement a single templated function and make two calls into it.
template<typename T>
Matrix& add_or_sub (const Matrix& M, const T &op){
for (int indexR = 0; indexR < rows; ++indexR)
for (int indexC = 0; indexC < cols; ++indexC)
Mat_p[indexR][indexC] = op(Mat_p[indexR][indexC], M[indexR][indexC]);
return *this;
}
Matrix& Matrix::operator+= (const Matrix& M){
return add_or_sub(M, std::plus());
}
Matrix& Matrix::operator-= (const Matrix& M){
return add_or_sub(M, std::minus());
}
I'm a bit late, but I guess the example is more complete. I would suggest writing a piecewise functor applicator which uses underlying scalar as operands, and returns the same type as well, and implement operators using this.
An example:
#include <iostream>
#include <functional>
using namespace std;
template <int Rows, int Cols, typename Scalar = int>
class Matrix {
public:
void piecewise_apply(const Matrix& other, std::function<Scalar(Scalar,Scalar)> f) {
for (int indexR = 0; indexR < Rows; ++indexR)
for (int indexC = 0; indexC < Cols; ++indexC)
data[indexR][indexC] = f(data[indexR][indexC], other.data[indexR][indexC]);
}
Matrix<Rows,Cols,Scalar>& operator+=(const Matrix<Rows,Cols,Scalar>& rhs) {
piecewise_apply(rhs, std::plus<Scalar>());
return *this;
}
Matrix<Rows,Cols,Scalar>& operator-=(const Matrix<Rows,Cols,Scalar>& rhs) {
piecewise_apply(rhs, std::minus<Scalar>());
return *this;
}
private:
Scalar data[Rows][Cols];
};
int main() {
Matrix<5,5> a;
Matrix<5,5> b;
a.piecewise_apply(b, [](int a, int b){return a*b;});
a -= b;
return 0;
}
The example is not complete, as it lacks initialization. Also there is no protection when &rhs == this (a interesting place for optimizations), and probably some more, but it shows the idea. As for code efficiency.. well you should rely on the compiler on this one.
One advantage of this approach is that, even if it's a bit slower in the default version, you can try writing piecewise_apply which uses more elaborate optimization techniques, like blocking, or parallelization, etc. and get speedups in various places.
For a simple version, like in your example, the copy-paste version is shorter, and easier to understand, so probably a better choice.
Related
Consider a simple vector class realization:
#include <algorithm>
class Vector {
public:
Vector(int _elementsCount)
: elementsCount(_elementsCount)
, elements(new float[_elementsCount])
{}
~Vector() {
delete[] elements;
}
Vector(const Vector& rhs) {
elementsCount = rhs.size();
elements = new float[elementsCount];
for (int i = 0; i < elementsCount; ++i)
(*this)[i] = rhs[i];
}
float& operator [](int i) {
return elements[i];
}
float operator [](int i) const {
return const_cast<Vector&>(*this)[i];
}
int size() const {
return elementsCount;
}
/*// Dot product
float operator *(const Vector& v) {
float res = 0;
for (int i = 0; i < size(); ++i)
res += (*this)[i] * v[i];
return res;
}*/
private:
int elementsCount;
float* elements;
};
// Multiplication by a scalar
Vector operator *(const Vector& v, float k) {
Vector res(v.size());
for (int i = 0; i < v.size(); ++i)
res[i] = v[i] * k;
return res;
}
// Dot product
float operator *(const Vector& v1, const Vector& v2) {
float res = 0;
for (int i = 0; i < std::min(v1.size(), v2.size()); ++i)
res += v1[i] * v2[i];
return res;
}
void main()
{
Vector v(2);
v * 3; // ambiguous
}
This code compiles. But if we uncomment * operator realization in the class and comment its global realization (dot product function), then there will be an error "'Vector::operator *': 2 overloads have similar conversions", because there is an ambiguity: whether to call the multiplication by a scalar or to interpret 3 as an argument to a parametrized constructor and to call the dot product. This makes sense. But I don't get what's the difference of declaring the * operator as a member function or as a global function. I thought they should be the same in the example like above, but it's not the case.
Added. The thing I most interested in is not how to avoid the ambiguity, but why there is an ambiguity in one case (when * is declared as a member) and there is no one in the other (when * is declared as a global function).
You need to make your constructor explicit:
explicit Vector(int _elementsCount) { ... }
The reason for the ambiguity is that the compiler can't decide whether it should implicitly convert a int value to a Vector and invoke Vector::operator*, or implicitly convert a int value to a float and use operator*(const Vector&, float).
By using explicit, such conversions are forbidden, and you must use Vector(3) if you want "3" to be a Vector.
As a side-note, you should make the operator const, since it does not modify the object. Making it const will also allow it to be used with a const Vector:
float operator *(const Vector& v) const { ... }
Beware that will still conflict with your other overload:
float operator *(const Vector& v1, const Vector& v2)
There is no reason to have both. Choose either the member function or the global function and remove the other.
I created class Matrix and overloaded operator* for matrix multiplication. Inside the operator the calculations are correct but the returned result is different than this.
I tried changing this function from a friend function to a method but I got the same result.
Moreover I overloaded operators like +, - and they work fine
#include <iostream>
#include <math.h>
template<typename T> class Matrix;
template<typename T> Matrix<T> operator * (const Matrix<T>&, const Matrix<T>&);
template <typename T> class Matrix
{
public:
T *arr = nullptr;
int r, c;
friend Matrix<T> operator * <> (const Matrix<T>&, const Matrix<T>&);
Matrix(T *a, int r, int c) //parametrized constructor
{
this->arr = a;
this->r = r;
this->c = c;
}
void Print()
{
for(int i=0; i<r; i++)
{
std::cout<<"|";
for(int j=0; j<c; j++)
{
std::cout<<*(this->arr+i*c+j)<<" ";
}
std::cout<<'\b';
std::cout<<"|";
std::cout<<std::endl;
}
std::cout<<std::endl;
}
};
template <typename T> Matrix<T> operator * (const Matrix<T> &M1, const Matrix<T> &M2)
{
int r = M2.r;
int c = M1.c;
int l = M1.r;
T arr[r*c];
for(int i=0; i<r; i++)
{
for(int j=0; j<c; j++)
{
arr[i*r+j]=0;
for(int k=0; k<l; k++)
{
arr[i*r+j]+=(M1.arr[k*r+j]*M2.arr[i*l+k]);
}
std::cout<<std::endl;
}
}
//Matrix<T> x(arr, r, c);
//x.Print(); -this returns correct matrix
return Matrix<T>(arr, r, c);
}
Main
int main()
{
//here I created matrixes a and b but skipped this part of code
Matrix<int> c = a*b;
c.Print(); // - this returns wrong matrix
}
As you can see, c and x are matrices created from the same data, but I'm getting two different results.
|22 28|
|49 64|
from x.Print(), and
|4761920 4557403|
|4199040 7011960|
from c.Print().
The issue is that the Matrix constructor retains a pointer to an object that's allocated on the stack (arr). Once arr goes out of scope, any attempt to dereference the pointer will result in undefined behaviour.
You need to find a different way to manage the lifetime of the matrix data (for example, by having the matrix class keep its own copy of it).
Thanks for answers, it let me (at least partially) understand this situation.
Changing T *arr to std::vector<T> arr solved the problem.
First I have Matrix template Matrix< typename T, int Roz> and specialization of this template Matrix. But the specialization is create with constructor where argument is a size of matrix. So in example code A and Z have the same dimension. So I want to make add operator work with it. But complier say: error: no match for 'operator+' in 'Z + A'. So how I need to write operator+ for Matrix wich will be work with Matrix?
Code of Matrix templates below:
template<typename T,int Roz>
class Matrix
{
public:
T tab[Roz][Roz];
int z=Roz;
Matrix()
{
for(int i=0;i<Roz;++i)
for(int j=0;j<Roz;++j)
tab[i][j]=0;
}
T& operator()(int x,int y){
return tab[x-1][y-1];
}
//Problematic operator
Matrix& operator+(Matrix<T,Roz> b)
{
Matrix<T,Roz> tmp;
for(int i=0;i<Roz;++i)
for(int j=0;j<Roz;++j)
tmp.tab[i][j]=this->tab[i][j]+b.tab[i][j];
}
friend ostream& operator<<(ostream& out, Matrix<T,Roz> &v)
{
for(int i=0;i<v.z;++i)
{
for(int j=0;j<v.z;++j)
out<<v.tab[i][j]<<" ";
out<<endl;
}
return out;
}
};
//Specialization template
template<class T>
class Matrix<T,0>
{
private:
Matrix()
{
}
public:
vector<vector<T> > tab;
int z=0;
Matrix(int z)
{
for(int i=0;i<z;++i)
tab.push_back(vector<T>(z));
this->z = z;
for(int i=0;i<z;++i)
for(int j=0;j<z;++j)
tab[i][j]=0;
}
T& operator()(int x,int y){
return tab[x-1][y-1];
}
//Problematic operator
Matrix& operator+(Matrix<T,0> b)
{
Matrix<T,0> tmp(b.z);
for(int i=0;i<z;++i)
for(int j=0;j<z;++j)
tmp.tab[i][j]=this->tab[i][j]+b.tab[i][j];
}
//Problematic operator
Matrix& operator+(Matrix<T,0> &b)
{
Matrix<T,0> tmp(b.z);
for(int i=0;i<z;++i)
for(int j=0;j<z;++j)
tmp.tab[i][j]=this->tab[i][j]+b.tab[i][j];
}
friend ostream& operator<<(ostream& out, Matrix<T,0> &v)
{
for(int i=0;i<v.z;++i)
{
for(int j=0;j<v.z;++j)
out<<v.tab[i][j]<<" ";
out<<endl;
}
return out;
}
};
When I try add for example Matrix < int,3 > and Matrix < int, 0 > this make error. How I must definie operator+ in both templates they will work together?May I have to overload operator+ in specialization template?
The code below makes error when I try add A + Z.
int main()
{
Matrix<int,3> A, B;
Matrix<int, 4> C;
Matrix<int, 0> Z(3);
A(1,1)=1;
B(1,1)=2;
Z(1,1)=1;
Z + A;//<------- here error between diffrent instance of Matrix template
}
I don't really know why you wish to add up matrices of different dimensions, but in order to do it, you must turn the method into a method template on the dimension of the matrix argument:
#include <type_traits>
template <int Roz2>
Matrix& operator+(Matrix<T,Roz2> b)
{
// check matrix argument size compatibility
std::static_assert(Roz2 >= Roz, "incompatible matrices for operator+()");
Matrix<T,Roz> tmp;
for(int i=0;i<Roz;++i)
for(int j=0;j<Roz;++j)
tmp.tab[i][j]=this->tab[i][j]+b.tab[i][j];
}
Since Matrix<T,0> is a specialization to handle dynamic dimension, you must specialize the operator for it:
// in the generic template
Matrix& operator+(Matrix<T,0> b)
{
assert (b.z < Roz, "incompatible dynamic matrix for operator+");
Matrix<T,0> tmp(b.Roz);;
for(int i=0;i<Roz;++i)
for(int j=0;j<Roz;++j)
tmp.tab[i][j]=this->tab[i][j]+b.tab[i][j];
}
and in Matrix<T,0>:
template <int Roz>
Matrix& operator+(Matrix<T,Roz> b)
{
assert(Roz >= z,"....");
Matrix<T,0> tmp(b.z);
for(int i=0;i<z;++i)
for(int j=0;j<z;++j)
tmp.tab[i][j]=this->tab[i][j]+b.tab[i][j];
}
In the above solution, however, the operator is not commutative. In order to make it so, we need to do some change:
// define a min operator as constexpr in case the existing one is not
template<typename T> constexpr
T const& rmin(T const& a, T const& b) {
return a > b ? b : a;
}
// generic operator
template <int Roz2>
Matrix<T,rmin(Roz,Roz2)>& operator+(Matrix<T,Roz2> b)
{
constexpr int R = min(Roz,Roz2);
Matrix<T,R> tmp;
for(int i=0;i<R;;++i)
for(int j=0;j<R;++j)
tmp.tab[i][j]=this->tab[i][j]+b.tab[i][j];
}
// specialized operator on Roz=0 argument
Matrix<T,0>& operator+(Matrix<T,0> b)
{
const int r = min(z,b.z);
Matrix<T,0> tmp(r);
for(int i=0;i<r;;++i)
for(int j=0;j<r;++j)
tmp.tab[i][j]=this->tab[i][j]+b.tab[i][j];
}
// specialized operator in Roz=0 template
Matrix& operator+(Matrix<T,Roz> b)
{
return b + *this;
}
You will have to duplicate the code for const & parameters taking operators (or perhaps simply get rid of the non const parameter versions which don't seem very useful in that context).
Note the use of a static assert to limit the use of the operator with matrices of equal or larger dimension (this is a C++11 feature) in the non commutative version of the operators.
See this question on the topic of min not being a constexpr function template for further details.
My Matrx class is defined as
class Matrx
{
double A[50][50];
int m,n;
public:
Matrx(void);
Matrx(int a, int b)
{
m=a;
n=b;
}
Matrx operator +(Matrx b);
Matrx Transpose(Matrx b);
Matrx operator *(Matrx b);
CString printMatrx();
void readMatrx(double a[][]);
Matrx TransposeMat(Matrx b);
};
void Matrx::readMatrx(double a[][])
{
for(int i=0;i< m;i++)
{
for(int j=0;j< n;j++)
A[i][j]=a[i][j];
}
}
The intellisense gives error like the below
1 IntelliSense: an array may not have elements of this type d:\bmadaptive_dd_v1.02\matrx.h 17 27 TestServer
Why?
How to pass a two dimensional array as argument of the function?
The problem is that when passing multidimensional arrays as parameters in C++, you must specify the dimension of the outermost array. For example:
void ThisIsIllegal(int arr[][]); // Wrong!
void ThisIsAlsoIllegal(int arr[10][]); // Also wrong
void ThisIsLegal(int arr[][10]); // Okay
If you want to be able to have a function that takes in an array of any size, you can use templates:
template <size_t N, size_t M>
void ThisIsAlsoLegal(int (&arr)[M][N]);
This last version accepts any multidimensional array of the right type, and is probably what you're looking for.
You need to properly learn about arrays and pointers. This includes the lesson "huh! They are not as useful as I thought they were". After you've gotten familiar with how arrays and pointers work exactly you should rethink your design.
For example, in my opinion, the following design has lots of advantages:
#ifndef MATRIX_HPP_INCLUDED
#define MATRIX_HPP_INCLUDED
#include <vector>
#include <algorithm>
class matrix
{
public:
typedef std::vector<double>::size_type st;
matrix() : rows_(0), cols_(0) {}
matrix(int r, int c) : rows_(r), cols_(c), coeffs_(st(r)*c,0.0) {}
void reset(int r, int c)
{ rows_=r; cols_=c; coeffs_.clear(); coeffs_.resize(st(r)*c,0.0); }
int rows() const {return rows_;}
int cols() const {return cols_;}
double const& operator()(int i, int j) const {return coeffs_[indexof(i,j)];}
double & operator()(int i, int j) {return coeffs_[indexof(i,j)];}
double const* operator[](int i) const {return &coeffs_[indexof(i,0)];}
double * operator[](int i) {return &coeffs_[indexof(i,0)];}
void swap(matrix& that)
{
std::swap(this->rows_,that.rows_);
std::swap(this->cols_,that.cols_);
this->coeffs_.swap(that.coeffs_));
}
private:
int rows_, cols_;
std::vector<double> coeffs_;
st indexof(int i, int j) const {return st(i)*cols+j;} // row major storage
};
inline void swap(matrix& a, matrix& b) {a.swap(b);}
matrix& operator+=(matrix& lhs, matrix const& rhs);
matrix operator+(matrix const& lhs, matrix const& rhs);
matrix operator*(matrix const& lhs, matrix const& rhs);
inline matrix& operator*=(matrix& lhs, matrix const& rhs)
{ matrix tmp = lhs * rhs; swap(tmp,lhs); return lhs; }
...
#endif
This way you won't waste any space for small matrices, and you can support large matrices. Also, the use of std::vector instead of a pointer member which points to dynamically allocated memory removes the need to define your own copy constructor, assignment operator and destructor.
Of course, you could use boost::multi_array as a matrix replacement but using a custom matrix class allows you to declare overloaded operators in your own namespace which is desirable due to ADL (argument dependent lookup).
You might think that this doesn't really answer your question. In that case, let me stress that I think you don't fully understand how arrays and pointers work / behave. This is something you should look up in a decent C++ book. One could write many pages about this topic. You can't expect to see a short answer explaining all the quirks.
Check out the Definite C++ Book Guide thread.
You need to specify all but the first dimension, e.g.
void Matrx::readMatrx(double a[][50])
From this you should be able to see that you have a fundamental problem with the way you have implemented your class, but at least you should now be able to get the code to compile.
You can to specify all dimensions or only last dimension to pass an array:
void Matrx::readMatrx(double a[][50])
{
for(int i=0;i< m;i++)
{
for(int j=0;j< n;j++)
A[i][j]=a[i][j];
}
}
Thanks to all of you people...you were really helping...I have found myself a new definition of the class and the function definition for the matrix that fitted my need. I need you r comment on it...Below is the example of the class declaration..
#include<iostream>
#include"stdafx.h"
using namespace std;
const int M=100; const int N=100;
class Matrix
{
double A[M][N];
int m,n;
public:
Matrix(void);
Matrix(int a, int b)
{
m=a;
n=b;
for(int i=0;i<m;i++)
{
for(int j=0;j<m;j++)
A[i][j]=0.0;
}
}
Matrix operator +(Matrix b);
Matrix operator -(Matrix b);
Matrix operator *(Matrix b);
void TransPose(Matrix b);
CString printMatrix();
void readMatrix(double*);
};
and then the function implementation
#include "stdafx.h"
#include "Matrix.h"
Matrix::Matrix(void)
{
}
Matrix Matrix::operator *(Matrix b)
{
Matrix c(m,m);
if(n!=b.m)
{
HWND hndOwner(0);
MessageBoxW(hndOwner,L"Multiplication not possible row and column does not match",L"Error",NULL);
Matrix errMat(1,0);
double er[1][1]={0}; errMat.readMatrix((double *)er);
return errMat;
}
for(int i=0;i< m;i++)
{
for(int k=0;k< m;k++)
{
c.A[i][k]=0;
for(int j=0;j< n;j++)
{
c.A[i][k] = c.A[i][k]+(A[i][j] * b.A[j][k]) ;
}
}
}
return c;
}
Matrix Matrix::operator +(Matrix b)
{
Matrix c(m,n);
if((n!=b.n)||(m!=b.m))
{
HWND hndOwner(0);
MessageBoxW(hndOwner,L"Addition not possible row and column does not match",L"Error",NULL);
Matrix errMat(1,0);
double er[1][1]={0}; errMat.readMatrix((double *)er);
return errMat;
}
for(int i=0;i<m;i++)
{
for(int j=0;j< n;j++)
{
c.A[i][j]=0.0;
}
}
for(int i=0;i< m;i++)
{
for(int j=0;j< n;j++)
{
c.A[i][j]=A[i][j]+b.A[i][j];
}
}
return c;
}
CString Matrix::printMatrix()
{
CString strB(" "),strDisp;
for(int iRow=0;iRow<m;iRow++)
{
for(int iColumn=0;iColumn<n;iColumn++)
{
strB.Format(L"%lf ",A[iRow][iColumn]);
strDisp+=strB;
}
strDisp+="\r\n";
}
return strDisp;
}
void Matrix::readMatrix(double *ptrarr)
{
for(int i=0;i< m;i++)
{
for(int j=0;j< n;j++)
A[i][j]=*(ptrarr+i*n+j);
}
}
void Matrix::TransPose(Matrix b)
{
for(int i=0;i<b.n;i++)
{
for(int j=0;j<b.m;j++)
A[i][j]=b.A[j][i];
}
}
The simple codes in the above are working well till now...if you have any suggestion for the improvement please suggest..
You're lucky, then because:
for(int j=0;j<m;j++)
A[i][j]=0.0;
should probably be:
for(int j=0;j<**n**;j++)
A[i][j]=0.0;
I, like so many programmers before me, am tearing my hair out writing the right-of-passage-matrix-class-in-C++. I have never done very serious operator overloading and this is causing issues. Essentially, by stepping through
This is what I call to cause the problems.
cMatrix Kev = CT::cMatrix::GetUnitMatrix(4, true);
Kev *= 4.0f;
cMatrix Baz = Kev;
Kev = Kev+Baz; //HERE!
What seems to be happening according to the debugger is that Kev and Baz are added but then the value is lost and when it comes to reassigning to Kev, the memory is just its default dodgy values. How do I overload my operators to allow for this statement?
My (stripped down) code is below.
//header
class cMatrix
{
private:
float* _internal;
UInt32 _r;
UInt32 _c;
bool _zeroindexed;
//fast, assumes zero index, no safety checks
float cMatrix::_getelement(UInt32 r, UInt32 c)
{
return _internal[(r*this->_c)+c];
}
void cMatrix::_setelement(UInt32 r, UInt32 c, float Value)
{
_internal[(r*this->_c)+c] = Value;
}
public:
cMatrix(UInt32 r, UInt32 c, bool IsZeroIndexed);
cMatrix( cMatrix& m);
~cMatrix(void);
//operators
cMatrix& operator + (cMatrix m);
cMatrix& operator += (cMatrix m);
cMatrix& operator = (const cMatrix &m);
};
//stripped source file
cMatrix::cMatrix(cMatrix& m)
{
_r = m._r;
_c = m._c;
_zeroindexed = m._zeroindexed;
_internal = new float[_r*_c];
UInt32 size = GetElementCount();
for (UInt32 i = 0; i < size; i++)
{
_internal[i] = m._internal[i];
}
}
cMatrix::~cMatrix(void)
{
delete[] _internal;
}
cMatrix& cMatrix::operator+(cMatrix m)
{
return cMatrix(*this) += m;
}
cMatrix& cMatrix::operator*(float f)
{
return cMatrix(*this) *= f;
}
cMatrix& cMatrix::operator*=(float f)
{
UInt32 size = GetElementCount();
for (UInt32 i = 0; i < size; i++)
{
_internal[i] *= f;
}
return *this;
}
cMatrix& cMatrix::operator+=(cMatrix m)
{
if (_c != m._c || _r != m._r)
{
throw new cCTException("Cannot add two matrix classes of different sizes.");
}
if (!(_zeroindexed && m._zeroindexed))
{
throw new cCTException("Zero-Indexed mismatch.");
}
for (UInt32 row = 0; row < _r; row++)
{
for (UInt32 column = 0; column < _c; column++)
{
float Current = _getelement(row, column) + m._getelement(row, column);
_setelement(row, column, Current);
}
}
return *this;
}
cMatrix& cMatrix::operator=(const cMatrix &m)
{
if (this != &m)
{
_r = m._r;
_c = m._c;
_zeroindexed = m._zeroindexed;
delete[] _internal;
_internal = new float[_r*_c];
UInt32 size = GetElementCount();
for (UInt32 i = 0; i < size; i++)
{
_internal[i] = m._internal[i];
}
}
return *this;
}
Your operators + and * must return by value, not by reference. You're returning a temporary variable by reference. Also, you're arguments are passed by value when it should be a const reference:
cMatrix cMatrix::operator+(cMatrix const& m)
{
cMatrix matrix(*this);
matrix += m;
return matrix;
}
cMatrix cMatrix::operator*(float f)
{
cMatrix matrix(*this);
matrix *= m;
return matrix;
}
You should take a look at Boost.Operators. This would let you implement only operator*= and operator+= and automatically provide correct implementations for operator+ and operator*.
PS: If you implement your matrix class just for the learning experience, don't hesitate to look at other implementations like the Matrix Template Library.
PPS: If you don't want to use boost, or if you just want to understand the best practice, take a look at Boost.Operator and do what they do.
IMO the canonical form of overloading addition is this:
class X {
public:
X& operator+=(const X& rhs) { /*add rhs to *this*/ }
};
inline X operator+(X lhs, const X& rhs) {lhs+=rhs; return lhs;}
The same goes for -, *, /, where applicable.
Note that + returns a copy, not a reference. That's important, because A+B creates a new value, so it cannot return a reference to an existing one.
Also, it is a free function. IMO it's best to implement those of the binary operators which can be implement either as a member or as a free function as free functions, if they treat their operands symmetrically (as does +), and as member functions, if they treat their operands asymmetrically (as +=, which changes its left argument. If you implement operator+ as a member, you will have to make the function const (X operator+(const X& rhs) const), so that it can be invoked for constant elements on the left side.