模板类的成员函数的参数

时间:2014-11-26 16:57:22

标签: c++ templates member-functions

我正在努力更好地理解模板,并转向了良好的'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未在任何地方声明。应该在何处/如何宣布?

4 个答案:

答案 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专门用于涵盖这两种情况。对?