Hello,
I have a peculiar problem. I have written a simple matrix class that uses expression templates. On Microsoft C++ and Intel C++ compilers it works just fine. However on Linux GCC it works quite unexpectedly:
When trying to use a line of code using expression templates I get an error:
error: no matching function for call to ‘mfml::MatrixMatrixElementWiseOperation<double, long unsigned int, mfml::DataContainer<double, long unsigned int>, mfml::meta::plus<double>, mfml::DataContainer<double, long unsigned int> >::MatrixMatrixElementWiseOperation()’
and debugger points do Matrix class move constructor (which is absolutely different class). However if I remove the definition of the move constructor and leave only its declaration everything works fine. But i have no idea what is really happenning there, as there should undefined reference error occur. Nothing like that happens. To make the following code work, just comment out Matrix move constructor definition, and leave its declaration only.
Below, used code samples:
main.cpp:
#include <iostream>
#include "../mfmlMatrixTemplate.h"
#include "../mfmlMatrixOperatorsET.h"
using namespace std;
int main()
{
mfml::Matrix<double, unsigned long> x,y,z;
x.Resize(10,1);
y.Resize(10,1);
z=x+y;
cout << "done" << endl;
return 0;
}
DataContainer class:
#ifndef MFML_DATA_CONTAINER_H_INCLUDED
#define MFML_DATA_CONTAINER_H_INCLUDED
namespace mfml{
template <class DATA_TYPE,class INT_TYPE>
class DataContainer
{
public:
DATA_TYPE *Data;
INT_TYPE Rows,Cols;
DataContainer() : Data(NULL), Rows(INT_TYPE(0)), Cols(INT_TYPE(0))
{
}
DataContainer(const DataContainer &&dc)
{
Data=NULL;
Rows=0;
Cols=0;
std::swap(Data,dc.Data);
std::swap(Rows,dc.Rows);
std::swap(Cols,dc.Cols);
}
~DataContainer()
{
Free();
}
inline DATA_TYPE operator[] (INT_TYPE i) const { return Data[i]; }
inline DATA_TYPE& operator[] (INT_TYPE i) { return Data[i]; }
inline void Alloc(INT_TYPE rows,INT_TYPE cols)
{
if (rows>0 && cols>0)
{
Data=new DATA_TYPE[rows*cols];
Rows=rows;
Cols=cols;
}
}
inline void Free()
{
delete[] Data;
Data=NULL;
Rows=0;
Cols=0;
}
inline INT_TYPE NumOfElements() const { return Rows*Cols; }
inline INT_TYPE NumOfRows() const { return Rows; }
inline INT_TYPE NumOfCols() const { return Cols; }
private:
DataContainer(const DataContainer &dc) {}
DataContainer& operator=(const DataContainer &dc)
{
return *this;
}
};
} //namespace mfml
#endif // MFML_DATA_CONTAINER_H_INCLUDED
Matrix class:
#ifndef MFML_MATRIX_TEMPLATE_H_INCLUDED
#define MFML_MATRIX_TEMPLATE_H_INCLUDED
//-------------------C++ INCLUDES--------------------------BEGIN
#include <algorithm>
#include <vector>
#include <iostream>
#include <cmath>
#include <functional>
#ifdef _OPENMP
#include <omp.h>
#endif
//-------------------C++ INCLUDES--------------------------END
//-------------------MFML INCLUDES-------------------------BEGIN
#include "mfmlDataContainer.h"
//-------------------MFML INCLUDES-------------------------END
namespace mfml
{
template <class DATA_TYPE,class INT_TYPE=std::size_t,class DATA_CONTAINER=DataContainer<DATA_TYPE,INT_TYPE> >
class Matrix
{
//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
private:
DATA_CONTAINER dc;
inline void Alloc(INT_TYPE _Rows,INT_TYPE _Cols); //Allocates the memory for the Matrix.Data - to be used only when matrix is created, otherwise use Resize(RequiredRowsNumber,RequiredColumnsNumber)
inline void Free(); //Frees memory
Matrix(const Matrix<DATA_TYPE,INT_TYPE,DATA_CONTAINER> &M); //Copy cnstructor not to be used, therefore it is private. operator A=B should be used to copy
// Matrix(Matrix<DATA_TYPE,INT_TYPE,DATA_CONTAINER> &&M); //Move constructor
//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
public:
//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Matrix(); //Default constructor, creates an empty Matrix instance
Matrix(DATA_TYPE s); //Meritoric constructor with scalar value - creates matrix of size 1x1
Matrix(const DATA_CONTAINER &_dc);
Matrix(Matrix<DATA_TYPE,INT_TYPE,DATA_CONTAINER> &&M);
~Matrix(); //Destructor
//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
inline void Resize(INT_TYPE _Rows,INT_TYPE _Cols);
inline void ResizeNoCopyNoFill(INT_TYPE _Rows,INT_TYPE _Cols);
inline void Copy(const Matrix<DATA_TYPE,INT_TYPE,DATA_CONTAINER> &M);
inline operator DATA_TYPE() const; //Easy conversion from Matrix of size 1x1 to scalar s=M
DATA_TYPE operator[](INT_TYPE i) const;
inline Matrix<DATA_TYPE,INT_TYPE,DATA_CONTAINER>& operator =(const Matrix<DATA_TYPE,INT_TYPE,DATA_CONTAINER>& M);
inline Matrix<DATA_TYPE,INT_TYPE,DATA_CONTAINER>& operator =(Matrix<DATA_TYPE,INT_TYPE,DATA_CONTAINER>&& M);
//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
inline DATA_TYPE* GetDataPtr() const {return dc.Data;} //Method returns pointer to Data, method required for compatibility with Basic Operations (bo:: namespace) functions
inline const DATA_CONTAINER& dcRef() const {return dc;}
//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
inline INT_TYPE NumOfElements()const {return dc.NumOfElements();} //Method returns the number of elements stored in the matrix
inline INT_TYPE NumOfRows() const {return dc.NumOfRows();} //Method returns the number of rows in the matrix
inline INT_TYPE NumOfCols() const {return dc.NumOfCols();} //Method returns the number of columns in the matrix
inline INT_TYPE& RowsRef() {return dc.Rows;};
inline INT_TYPE& ColsRef() {return dc.Cols;};
inline bool IsEmpty() {return (dc.Rows==0 && dc.Cols==0);}
//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
template <typename Expr>
Matrix& operator = (const Matrix<DATA_TYPE,INT_TYPE,Expr>& Rhs)
{
Resize(Rhs.NumOfRows(),Rhs.NumOfCols());
#ifdef mfmlSerialOnly
for (INT_TYPE i = 0; i < Rhs.NumOfElements(); i++) dc[i] = Rhs[i];
#else
INT_TYPE NE=Rhs.NumOfElements();
if (NE<100)
{
for (INT_TYPE i = 0; i < NE; i++) dc[i] = Rhs[i];
}
else
{
DATA_CONTAINER &dcp=dc;
#pragma omp parallel for default(none) shared(dcp,Rhs,NE)
for (INT_TYPE i = 0; i < NE; i++) dcp[i] = Rhs[i];
}
#endif
return *this;
}
}; //CLASS DEFINITION END
//DEFAULT CONSTRUCTOR
template <class DATA_TYPE,class INT_TYPE,class DATA_CONTAINER>
inline Matrix<DATA_TYPE,INT_TYPE,DATA_CONTAINER>::Matrix() : dc()
{ }
//COPY CTR - PRIVATE TO AVOID USING IT
template <class DATA_TYPE,class INT_TYPE,class DATA_CONTAINER>
inline Matrix<DATA_TYPE,INT_TYPE,DATA_CONTAINER>::Matrix(const Matrix<DATA_TYPE,INT_TYPE,DATA_CONTAINER> &M) //: dc(M.dc)
{
std::cout<<"cpy ctr"<<std::endl;
}
//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
template <class DATA_TYPE,class INT_TYPE,class DATA_CONTAINER>
inline Matrix<DATA_TYPE,INT_TYPE,DATA_CONTAINER>::Matrix(const DATA_CONTAINER &_dc) : dc(_dc)
{ std::cout<<"Matrix<DATA_TYPE,INT_TYPE,DATA_CONTAINER>::Matrix(const DATA_CONTAINER &_dc)"<<std::endl; }
//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
/*=============================================================================================================
COMMENT THE FOLLOWING DEFINITION TO MAKE EVERYTHING WORK
=============================================================================================================*/
template <class DATA_TYPE,class INT_TYPE,class DATA_CONTAINER>
inline Matrix<DATA_TYPE,INT_TYPE,DATA_CONTAINER>::Matrix(Matrix<DATA_TYPE,INT_TYPE,DATA_CONTAINER> &&M)
{
std::cout<<"move ctr"<<std::endl;
dc.Data=NULL;
dc.Rows=0;
dc.Cols=0;
std::swap(dc.Data,M.dc.Data);
std::swap(dc.Rows,M.dc.Rows);
std::swap(dc.Cols,M.dc.Cols);
}
//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
/*
Destructor. Removes the memory allocated previously.
*/
template <class DATA_TYPE,class INT_TYPE,class DATA_CONTAINER>
inline Matrix<DATA_TYPE,INT_TYPE,DATA_CONTAINER>::~Matrix()
{
Free();
}
template <class DATA_TYPE,class INT_TYPE,class DATA_CONTAINER>
inline void Matrix<DATA_TYPE,INT_TYPE,DATA_CONTAINER>::Alloc(INT_TYPE _Rows,INT_TYPE _Cols)
{
dc.Alloc(_Rows,_Cols);
}
template <class DATA_TYPE,class INT_TYPE,class DATA_CONTAINER>
inline void Matrix<DATA_TYPE,INT_TYPE,DATA_CONTAINER>::Free() //deallocates memory
{
dc.Free();
}
template <class DATA_TYPE,class INT_TYPE,class DATA_CONTAINER>
inline void Matrix<DATA_TYPE,INT_TYPE,DATA_CONTAINER>::Resize(INT_TYPE _Rows,INT_TYPE _Cols) //resizes the matrix but doesnt copy the values nor fills the empty places
{
if (dc.Rows!=_Rows || dc.Cols!=_Cols)
{
INT_TYPE NewNumberOfElements=_Rows*_Cols;
if (dc.Rows==0 && dc.Cols==0) Alloc(_Rows,_Cols); //data hasn't been initialized, or was deleted
else if (_Rows==0 || _Cols==0) Free(); //if one of dimensions is to be zero - delete matrix
else if (NewNumberOfElements!=NumOfElements()) //else - resize and copy values
{
DATA_TYPE *tmp=new DATA_TYPE[NewNumberOfElements];
delete[] dc.Data;
dc.Data=tmp;
dc.Rows=_Rows;
dc.Cols=_Cols;
}
else //size hasn't changed, only change od Rows/Columns is required
{
dc.Rows=_Rows;
dc.Cols=_Cols;
}
}
}
template <class DATA_TYPE,class INT_TYPE,class DATA_CONTAINER>
inline Matrix<DATA_TYPE,INT_TYPE,DATA_CONTAINER>& Matrix<DATA_TYPE,INT_TYPE,DATA_CONTAINER>::operator =(const Matrix<DATA_TYPE,INT_TYPE,DATA_CONTAINER>& M)
{
std::cout<<"copy operator"<<std::endl;
Copy(M);
return *this;
}
//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
/*
Move operator.
*/
template <class DATA_TYPE,class INT_TYPE,class DATA_CONTAINER>
inline Matrix<DATA_TYPE,INT_TYPE,DATA_CONTAINER>& Matrix<DATA_TYPE,INT_TYPE,DATA_CONTAINER>::operator =(Matrix<DATA_TYPE,INT_TYPE,DATA_CONTAINER>&& M)
{
std::cout<<"move operator"<<std::endl;
if (this!=&M)
{
std::swap(dc.Rows,M.dc.Rows);
std::swap(dc.Cols,M.dc.Cols);
std::swap(dc.Data,M.dc.Data);
}
return *this;
}
template <class DATA_TYPE,class INT_TYPE,class DATA_CONTAINER>
inline void Matrix<DATA_TYPE,INT_TYPE,DATA_CONTAINER>::Copy(const Matrix<DATA_TYPE,INT_TYPE,DATA_CONTAINER> &M) //copies matrix M to the current matrix
{
if (&M!=this)
{
if (!M.IsEmpty())
{
INT_TYPE MNumOfElements=M.NumOfElements();
if (MNumOfElements!=NumOfElements())
{
Free();
Alloc(M.dc.Rows,M.dc.Cols);
}
else
{
dc.Rows=M.dc.Rows;
dc.Cols=M.dc.Cols;
}
#if ((defined WINDOWS_MSVCC_32) || (defined WINDOWS_MSVCC_64))
std::copy(M.dc.Data,M.dc.Data+MNumOfElements,stdext::checked_array_iterator<DATA_TYPE*>( dc.Data, MNumOfElements ));
#else
std::copy(M.dc.Data,M.dc.Data+MNumOfElements,dc.Data);
#endif
} else Free();
}
}
template <class DATA_TYPE,class INT_TYPE,class DATA_CONTAINER>
DATA_TYPE Matrix<DATA_TYPE,INT_TYPE,DATA_CONTAINER>::operator[](INT_TYPE i) const
{
return dc[i];
}
} //namespace mmml
#endif // MATRIX_H_INCLUDED
Expression template:
#ifndef MFML_EXPRESSION_TEMPLATES_H_INCLUDED
#define MFML_EXPRESSION_TEMPLATES_H_INCLUDED
#include <cmath>
namespace mfml{
namespace meta{
template<class DATA_TYPE>
struct plus
{
inline static DATA_TYPE apply(DATA_TYPE a,DATA_TYPE b) { return a+b; }
};
} //namespace meta
template <class DATA_TYPE,class INT_TYPE, class Lhs, class Op, class Rhs>
class MatrixMatrixElementWiseOperation
{
public:
inline MatrixMatrixElementWiseOperation(const Lhs& a, const Rhs& b) : Op1(a) , Op2(b)
{
}
inline DATA_TYPE operator[] (INT_TYPE i) const {return Op::apply(Op1[i],Op2[i]); }
inline INT_TYPE NumOfElements() const { return Op1.NumOfElements(); }
inline INT_TYPE NumOfRows() const { return Op1.NumOfRows(); }
inline INT_TYPE NumOfCols() const { return Op1.NumOfCols(); }
void Free () {}
~MatrixMatrixElementWiseOperation() {}
private:
const Lhs& Op1;
const Rhs& Op2;
};
} //namespace mfml
#endif // MFMLEXPRESSIONTEMPLATES_H_INCLUDED
Expression template operator:
#ifndef MFML_MATRIX_OPERATORS_ET_H
#define MFML_MATRIX_OPERATORS_ET_H
/*
This file contains definitions and sources of EXPRESSION TEMPLATE versions of operators and functions
*/
#include "mfmlMatrixExpressionTemplates.h"
namespace mfml{
template <class DATA_TYPE,class INT_TYPE, class Lhs, class Rhs>
inline Matrix<DATA_TYPE,INT_TYPE,MatrixMatrixElementWiseOperation<DATA_TYPE,INT_TYPE,Lhs,meta::plus<DATA_TYPE>,Rhs> >
operator + (const Matrix<DATA_TYPE,INT_TYPE, Lhs>& lhs, const Matrix<DATA_TYPE,INT_TYPE, Rhs>& rhs)
{
std::cout<<"dupa.8"<<std::endl;
if (lhs.NumOfRows()!=rhs.NumOfRows() || lhs.NumOfCols()!=rhs.NumOfCols())
{
std::cout<<"throwing InconsistientRowColumnDimensionsException"<<std::endl;
}
return Matrix<DATA_TYPE,INT_TYPE,MatrixMatrixElementWiseOperation<DATA_TYPE,INT_TYPE,Lhs,meta::plus<DATA_TYPE>,Rhs> >
(MatrixMatrixElementWiseOperation<DATA_TYPE,INT_TYPE,Lhs,meta::plus<DATA_TYPE>,Rhs>(lhs.dcRef(), rhs.dcRef()));
}
} //namespace mfml
#endif
Regards,
Misery