我正在努力更好地理解模板,并转向了良好的'ole矩阵类。我知道eigen,armadillo等。我的目的是更好地理解模板。我的问题是你如何获得一个成员函数来获取一个参数,该参数是同一模板类的一个对象,但具有不同的特化?
例如,我试图放在一起的矩阵类需要两个模板参数 - 行数和列数。此外,任何mxn矩阵对象(Matrix<mRows,nCols>
)都应该能够获取一个nxp矩阵对象(Matrix<nCols,pCols>
)并将它们相乘并返回一个mxp矩阵对象(Matrix<mRows,pCols>
):
template <unsigned mRows, unsigned nCols>
class Matrix
{
private:
double matrixData[mRows][nCols];
//...other stuff
public:
//...other stuff
Matrix operator * (const Matrix<nCols, pCols>& rhs);
}
// simple naive matrix multiplication method
template <unsigned mRows, unsigned nCols>
Matrix<nCols,pCols> Matrix<mRows, nCols>::operator * (const Matrix<nCols,pCols>& rhs)
{
Matrix<nCols,pCols> temp();
for (int r = 0; r<mRows; ++r)
{
for(int c = 0;c<pCols;++c)
{
temp.matrixData[r][c]=0;
for (int elem = 0; elem<nCols;++elem)
{
temp.matrixData[r][c]+= matrixData[r][elem]*rhs.matrixData[elem][c];
}
}
}
return temp;
}
主要功能如下:
int main()
{
Matrix<2,3> m1;
Matrix<3,4> m2;
//...initialize matrices...
Matrix<2,4> m3 = m1 * m2;
}
这不起作用,因为pCols未在任何地方声明。应该在何处/如何宣布?
答案 0 :(得分:1)
自己制作operator*
成员函数模板。即在类模板中写入
template <unsigned pCols>
Matrix operator * (const Matrix<nCols, pCols>& rhs);
外面使用两个参数列表:
template <unsigned mRows, unsigned nCols>
template <unsigned pCols>
Matrix<mRows, pCols> Matrix<mRows, nCols>::operator * (const Matrix<nCols,pCols>& rhs)
但是,我建议您使用friend
非会员功能。
答案 1 :(得分:1)
在您的情况下,您必须使用函数模板定义中可用的模板参数来专门化Matrix类:
template <unsigned mRows, unsigned nCols>
Matrix<mRows,nCols> Matrix<mRows, nCols>::operator * (const Matrix<nCols,mRows>& rhs)
然后,您最好在声明和定义中为模板参数使用一致的命名约定。
将模板参数视为可用于在其后面的实体中使用的类型/常量。声明在这种情况下定义本质上是独立的实体(这就是为什么你需要在提供函数定义时第二次输入模板&lt;&gt;)。
编辑:再次仔细阅读问题之后,事实证明我的答案忽略了这一点。 Columbo的答案是要走的路。
答案 2 :(得分:0)
operator*
函数只需要一个模板参数。 RHS的行数必须与LHS的列数相同。
template <unsigned pCols>
Matrix<nRows, pCols> operator * (const Matrix<nCols, pCols>& rhs)
{
//...
}
答案 3 :(得分:0)
所以在弄乱了一段时间之后我终于得到了一个使用Columbo建议的解决方案。第一个解决方案将乘法运算符保持为成员函数,然后使所有特化项成为彼此的朋友,以便他们可以修改彼此的私有数据:
template <unsigned mRows, unsigned nCols>
class Matrix
{
private:
double matrixData[mRows][nCols];
public:
template<unsigned nRows, unsigned pCols> // make all specializations of the templates friends with each other
friend class Matrix;
// ... constructor and other operator definitions/prototypes here
// define proper matrix multiplication
// should be defined such that Matrix<mRows,pCols> = Matrix<mRows,nCols>*Matrix<nCols*pCols>
// since the inner dimensions of the matrix must be the same.
template <unsigned pCols>
Matrix<mRows,pCols> operator * (const Matrix<nCols, pCols>& rhs) const;
};
template <unsigned mRows, unsigned nCols>
template <unsigned pCols>
Matrix<mRows,pCols> Matrix<mRows, nCols>::operator * (const Matrix<nCols,pCols>& rhs) const
{
Matrix<mRows,pCols> temp;
for (unsigned r = 0; r<mRows; ++r)
{
for(unsigned c = 0;c<pCols;++c)
{
temp.matrixData[r][c]=0;
for (unsigned elem = 0; elem<nCols;++elem)
{
temp.matrixData[r][c]+= matrixData[r][elem]*rhs.matrixData[elem][c];
}
}
}
return temp;
}
第二个解决方案遵循Columbo的建议,使乘法运算符成为friend
非成员函数:
template <unsigned mRows, unsigned nCols>
class Matrix
{
private:
double matrixData[mRows][nCols];
public:
// ... constructor and other operator definitions/prototypes here
// define proper matrix multiplication
// should be defined such that Matrix<mRows,pCols> = Matrix<mRows,nCols>*Matrix<nCols*pCols>
// since the inner dimensions of the matrix must be the same.
template <unsigned m, unsigned n, unsigned p>
friend Matrix<m,p> operator * (const Matrix<m,n>& lhs, const Matrix<n, p>& rhs);
};
template <unsigned m, unsigned n, unsigned p>
Matrix<m,p> operator * (const Matrix<m,n>& lhs, const Matrix<n, p>& rhs)
{
Matrix<m,p> temp;
for (unsigned r = 0; r<m; ++r)
{
for(unsigned c = 0;c<p;++c)
{
temp.matrixData[r][c]=0;
for (unsigned elem = 0; elem<n;++elem)
{
temp.matrixData[r][c]+= lhs.matrixData[r][elem]*rhs.matrixData[elem][c];
}
}
}
return temp;
}
如果有人可以评论为什么一个比另一个好,那就太好了。我认为第二种解决方案更好,因为该功能专门针对不同的组合而不是整个类(对吧?)。例如,在Matrix<3,3> * Matrix<3,4>
vs Matrix<3,3> * Matrix<3,5>
中,Matrix<3,3>
类只需要专门设置一次,* operator
专门用于涵盖这两种情况。对?