template<typename T, size_t n, size_t m>
class Matrix;
template<typename T, size_t n, size_t m>
class EtMatrixAdd
{
public:
EtMatrixAdd( const Matrix<T, n, m>& lhs,
const Matrix<T, n, m>& rhs) : m_lhs(lhs), m_rhs(rhs
)
{
printf("EtMatrixAdd Constructor! \n");
}
T ElementAt(size_t nn, size_t mm) const
{
printf("EtMatrixAdd ElementAt! \n");
return m_lhs.ElementAt(nn, mm) + m_rhs.ElementAt(nn, mm);
}
private:
const Matrix<T, n, m>& m_lhs;
const Matrix<T, n, m>& m_rhs;
};
template<typename T, size_t n, size_t m>
class Matrix
{
public:
Matrix(){}
Matrix(const Matrix& rhs)
{
printf("Copy Constructor! \n");
for(int i=0; i<n; ++i)
for(int j=0; j<m; ++j)
ElementAt(i,j) = rhs.ElementAt(i,j);
}
Matrix& operator=(const Matrix& rhs)
{
printf("operator = #1! \n");
if( this != &rhs )
for(int i=0; i<n; ++i)
for(int j=0; j<m; ++j)
ElementAt(i,j) = rhs.ElementAt(i,j);
return *this;
}
Matrix<T, n, m>& operator=( const EtMatrixAdd<T, n, m>& rhs)
{
printf("operator = #2! \n");
for(int i=0; i<n; ++i)
for(int j=0; j<m; ++j)
ElementAt(i,j) = rhs.ElementAt(i,j);
return *this;
}
virtual ~Matrix() {}
const T& ElementAt(size_t nn, size_t mm) const
{ return arrData[nn][mm]; }
T& ElementAt(size_t nn, size_t mm)
{ return arrData[nn][mm]; }
private:
// C-style array for efficiency and locality of reference
T arrData[n][m];
};
template<typename T, size_t n, size_t m>
inline EtMatrixAdd<T, n, m> operator+( const Matrix<T, n, m>& lhs,
const Matrix<T, n, m>& rhs)
{
printf("EtMatrixAdd operator +! \n");
return EtMatrixAdd<T, n, m>(lhs, rhs);
}
template<typename T, size_t n, size_t m>
class Matrix;
template < typename T, size_t n, size_t m, typename LeftOp, typename RightOp>
class EtMatrixAdd
{
public:
EtMatrixAdd(const LeftOp& lhs, const RightOp& rhs) : m_lhs(lhs), m_rhs(rhs)
{
printf("EtMatrixAdd Constructor! \n");
}
T ElementAt(size_t nn, size_t mm) const
{
printf("EtMatrixAdd ElementAt! \n");
return m_lhs.ElementAt(nn, mm) + m_rhs.ElementAt(nn, mm);
}
private:
const LeftOp& m_lhs;
const RightOp& m_rhs;
};
template<typename T, size_t n, size_t m>
class Matrix
{
public:
Matrix(){printf("Constructor! \n");}
Matrix(const Matrix& rhs)
{
printf("Copy Constructor! \n");
for(int i=0; i<n; ++i)
for(int j=0; j<m; ++j)
ElementAt(i,j) = rhs.ElementAt(i,j);
}
Matrix& operator=(const Matrix& rhs)
{
printf("operator = #1! \n");
if( this != &rhs )
for(int i=0; i<n; ++i)
for(int j=0; j<m; ++j)
ElementAt(i,j) = rhs.ElementAt(i,j);
return *this;
}
template< typename TT, size_t nn, size_t mm, typename LeftOp, typename RightOp >
Matrix<T, nn, mm>& operator=( const EtMatrixAdd<TT, nn, mm, LeftOp, RightOp>& rhs)
{
for(int i=0; i<nn; ++i)
for(int j=0; j<mm; ++j)
ElementAt(i,j) = rhs.ElementAt(i,j);
return *this;
}
virtual ~Matrix() {}
const T& ElementAt(size_t nn, size_t mm) const
{ return arrData[nn][mm]; }
T& ElementAt(size_t nn, size_t mm)
{ return arrData[nn][mm]; }
private:
T arrData[n][m];
};
template<typename T, size_t n, size_t m>
inline EtMatrixAdd<T, n, m, Matrix<T, n, m>, Matrix<T, n, m> >
operator+ ( const Matrix<T, n, m>& lhs, const Matrix<T, n, m>& rhs )
{
printf("#1 operator + \n");
return EtMatrixAdd<T, n, m, Matrix<T, n, m>, Matrix<T, n, m> >
( lhs, rhs );
}
// 컴파일 시점에 재귀적인 생성자 호출 코드가 생성되며, RVO가 동작하게 된다.
template< typename T, size_t n, size_t m, typename LeftOp, typename RightOp >
inline EtMatrixAdd< T, n, m, EtMatrixAdd<T, n, m, LeftOp, RightOp>, Matrix<T, n, m> >
operator+( const EtMatrixAdd<T, n, m, LeftOp, RightOp>& lhs,
const Matrix<T, n, m>& rhs )
{
printf("#2 operator + \n");
return EtMatrixAdd<T, n, m,
EtMatrixAdd<T, n, m, LeftOp, RightOp>,
Matrix<T, n, m> > (lhs, rhs) ;
}
int main( int argc, char* argv [ ] )
{
Matrix<double, 1, 2> A;
Matrix<double, 1, 2> B;
Matrix<double, 1, 2> C;
Matrix<double, 1, 2> S ;
S = A + B + C ;
return 0;
EtMatrixAdd 에 LeftOp, RightOp 템플릿 인자를 추가함으로서 앞서의 문제를 해결했다.
이연산을 위해 컴파일러가 생성되는 코드는 아래처럼 작성한것과 동일하다.
typedef Matrix<double, n, m> Mat;
Temp1 = A + B;
=> EtMatrixAdd<double, n, m, Mat, Mat>
Temp2 = Temp1 + C;
=> EtMatrixAdd<double, n, m, EtMatrixAdd<double, n, m, Mat, Mat>, Mat>
S = Temp2;