【问题标题】:Parameter of member functions of template class模板类成员函数的参数
【发布时间】:2014-11-26 16:57:22
【问题描述】:

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

【问题讨论】:

  • 我明白这个课程的目的是更好地理解模板。但无论如何,您应该始终记住,编译器会为每个模板参数生成代码(与 java 泛型相反)。这意味着如果您将使用这个类来乘以不同大小的矩阵 ([N, M] * [M, K]),那么生成的代码量也将取决于大小的唯一三元组的数量 ([N, M, K])

标签: c++ templates member-functions


【解决方案1】:

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

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

那么你最好在声明和定义中为你的模板参数使用一致的命名约定。

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

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

【讨论】:

    【解决方案2】:

    自己制作operator* 成员函数模板。 IE。写在类模板里面

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

    【讨论】:

    • 我认为这是正确的想法——在类模板中,我不得不将类中的原型更改为 template &lt;unsigned pCols&gt; Matrix&lt;mRows,pCols&gt; operator * (const Matrix&lt;nCols, pCols&gt;&amp; rhs);,但是我无法访问班上。模板的一个特化不能访问同一模板的不同特化的私有成员吗?
    • @Jason 不,为什么会这样?它们是不同的类。
    • 如果你将两个Matrix&lt;3,3&gt; 相乘,它们就可以访问彼此的私有成员了。但是,Matrix&lt;3,3&gt; 乘以 Matrix&lt;3,4&gt; 显然你不能这样做,但如果你能做到就好了
    【解决方案3】:

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

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

    【讨论】:

      【解决方案4】:

      所以在搞砸了一段时间后,我终于有了一个使用哥伦布建议的解决方案。第一个解决方案将乘法运算符保留为成员函数,然后使所有特化彼此成为朋友,以便他们可以修改彼此的私有数据:

      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&lt;3,3&gt; * Matrix&lt;3,4&gt;Matrix&lt;3,3&gt; * Matrix&lt;3,5&gt; 中,Matrix&lt;3,3&gt; 类只需要专门化一次,* operator 将专门化这两种情况。对?

      【讨论】:

        猜你喜欢
        • 2018-12-16
        • 2023-04-02
        • 2011-07-06
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-07-02
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多