模板类的成员函数参数

Parameter of member functions of template class

本文关键字:函数 参数 成员      更新时间:2023-10-16

我正在尝试更好地理解模板,并转向好的'ole矩阵类。 我知道本征、犰狳等,我的目的是更好地理解模板。 我的问题是,如何让成员函数接受一个参数,该参数是同一模板类的对象,但具有不同的专用化?

例如,我尝试组合在一起的矩阵类需要两个模板参数 - 行数和列数。 此外,任何 m x n 矩阵对象 (Matrix<mRows,nCols> ) 应该能够取一个 n x p 矩阵对象 (Matrix<nCols,pCols> ) 并将它们相乘并返回一个 m x p 矩阵对象 (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 没有在任何地方声明。应该在哪里/如何声明?

您必须使用函数模板定义中可用的模板参数来专门化 Matrix 类,在这种情况下:

template <unsigned mRows, unsigned nCols>
Matrix<mRows,nCols> Matrix<mRows, nCols>::operator * (const Matrix<nCols,mRows>& rhs)

然后,最好在声明和定义中对模板参数使用一致的命名约定。

将模板参数视为可在其后实体中使用的类型/常量。声明是定义在此上下文中本质上是单独的实体(这就是为什么您需要在提供函数定义时第二次键入 template<>)。

编辑:再次仔细阅读问题后,事实证明我的答案没有抓住重点。哥伦布的答案是要走的路。

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非成员函数。

operator*函数只需要一个模板参数。RHS 的行数必须与 LHS 的列数相同。

template <unsigned pCols>
Matrix<nRows, pCols> operator * (const Matrix<nCols, pCols>& rhs)
{
  //...
}
因此,

在弄乱了一段时间之后,我终于有了使用哥伦布建议的解决方案。 第一种解决方案将乘法运算符保留为成员函数,然后使所有专业化彼此友好,以便它们可以修改彼此的私人数据:

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>Matrix<3,3> * Matrix<3,5>中,Matrix<3,3>类只需要专门化一次,而* operator类将专门涵盖这两种情况。右?