【问题标题】:Declare a partial specified templated matrix multiplication operator overload function as friend outside the class将部分指定的模板化矩阵乘法运算符重载函数声明为类外的友元
【发布时间】:2012-11-22 06:18:35
【问题描述】:

我在写一个矩阵基类,遇到了题主的问题。

这是我的声明。

template <typename T, size_t m, size_t n, typename _Prd>
template <size_t _m, size_t _n>
const Matrix<T,m,_n,_Prd> operator* (const Matrix<T,m,n,_Prd>& lhs, const Matrix<T,_m,_n,_Prd>& rhs) ; // matrix mult

和类内的朋友声明。

template <size_t _m, size_t _n>
friend const Matrix<T,m,_n,_Prd> operator* <>(const Matrix<T,m,n,_Prd>& lhs, const Matrix<T,_m,_n,_Prd>& rhs) ;

及实施:

template <typename T, size_t m, size_t n, typename _Prd>
template <size_t _m, size_t _n>
const Matrix<T,m,_n,_Prd> operator* (const Matrix<T,m,n,_Prd>& lhs, const Matrix<T,_m,_n,_Prd>& rhs) 
{
    assert (n == _m) ;
    Matrix<T,m,_n,_Prd> result ;

    for (size_t j = 0 ; j < m ; ++j)
        for (size_t i = 0 ; i < _n ; ++ i)

            for (size_t k = 0 ; k < n ; ++ k) 
                result.at(j,i) += lhs.at(j,k) * rhs.at(k,i) ;

    return result ;
}

但是这些不能编译,错误是:

In file included from main.cpp:13:
Matrix.hpp:43: error: too many template-parameter-lists
Matrix.hpp:66: error: invalid use of template-id ‘operator*<>’ in declaration of primary template
In file included from main.cpp:13:
Matrix.hpp:364: error: too many template-parameter-lists

我在同一班级遇到了另一个问题no matching function when return different template type from the original

更新

我按照下面的建议修改了,还是不行。

转发声明:

template <typename T, size_t m, size_t n, typename _Prd,size_t _m, size_t _n>
const Matrix<T,m,_n,_Prd> operator* (const Matrix<T,m,n,_Prd>& lhs, const Matrix<T,_m,_n,_Prd>& rhs) ; // matrix mult

类内的朋友声明:

template <size_t _m, size_t _n>
friend const Matrix<T,m,_n,_Prd> operator* (const Matrix<T,m,n,_Prd>& lhs, const Matrix<T,_m,_n,_Prd>& rhs) ;

实施:

template <typename T, size_t m, size_t n, typename _Prd,size_t _m, size_t _n>

const Matrix<T,m,_n,_Prd> operator* (const Matrix<T,m,n,_Prd>& lhs, const Matrix<T,_m,_n,_Prd>& rhs) 
{
    assert (n == _m) ;
    Matrix<T,m,_n,_Prd> result ;

    for (size_t j = 0 ; j < m ; ++j)
        for (size_t i = 0 ; i < _n ; ++ i)

            for (size_t k = 0 ; k < n ; ++ k) 
                result.at(j,i) += lhs.at(j,k) * rhs.at(k,i) ;

    return result ;
}

但是当我想这样使用它时:

Matrix<double,2,3> testmat8(10.0) ;
Matrix<double,3,4> testmat9(2.0) ;
Matrix<double,2,4> testmat10 ;
testmat10 = testmat8 * testmat9 ;

错误是:

main.cpp:143: undefined reference to `Matrix<double, 2ul, 4ul, std::equal_to<double> > const operator*<3ul, 4ul>(Matrix<double, 2ul, 3ul, std::equal_to<double> > const&, Matrix<double, 3ul, 4ul, std::equal_to<double> > const&)'

仍未解决...

更新2:

为了阐明我的目的,我编写了 3 个解决方法。但是,并非所有这些都按预期工作。

//member operator * rather than friend function
template <typename T, size_t m, size_t n, typename _Prd>
template<size_t _m, size_t _n>
Matrix<T,m,_n,_Prd> Matrix<T,m,n,_Prd>::operator *(const Matrix<T,_m,_n,_Prd> & rhs) const 
{
    assert (n == _m) ;
    Matrix<T,m,_n,_Prd> result ;
    for (size_t j = 0 ; j < m ; ++j)
        for (size_t i = 0 ; i < _n ; ++ i)
            for (size_t k = 0 ; k < n ; ++ k) 
                result.at(j,i) += this->at(j,k) * rhs.at(k,i) ;
    return result ;
}


//work around for *
template <typename T, size_t m, size_t n, typename _Prd>
template<size_t _m, size_t _n>
void Matrix<T,m,n,_Prd>::mul (Matrix<T,m,_n,_Prd> & result, const Matrix<T,m,n,_Prd> & A, const Matrix<T,_m,_n,_Prd> & B) 
{
    assert (n == _m) ;
    for (size_t j = 0 ; j < m ; ++j)
        for (size_t i = 0 ; i < _n ; ++ i)

            for (size_t k = 0 ; k < n ; ++ k) 
                result.at(j,i) += A.at(j,k) * B.at(k,i) ;
}

template <typename T, size_t m, size_t n, typename _Prd>
template<size_t _m, size_t _n>
Matrix<T,m,_n,_Prd> Matrix<T,m,n,_Prd>::mul(const Matrix<T,_m,_n,_Prd> & B) const 
{
    assert (n == _m) ;
    Matrix<T,m,_n,_Prd> result ;

    for (size_t j = 0 ; j < m ; ++j)
        for (size_t i = 0 ; i < _n ; ++ i)

            for (size_t k = 0 ; k < n ; ++ k) 
                result.at(j,i) += this->at(j,k) * B.at(k,i) ;

    return result ;
}

我这样称呼他们:

    testmat10 = testmat8 * testmat9 ; //works, but I have to comment out the friend operator * overload outside of the class.
    testmat10 = testmat8.mul(testmat9) ; //works, but mul() has to be a member, not as expected as a friend .
    Matrix<double,2,3>::mul(testmat10, testmat8, testmat9) ; 
//works, but this is ridiculous, for a static function, how would I avoid use <double,2,3> as the testmat8's template before using mul? I shouldn't have used template when I use mul in this way.

但是我想要的答案是有人可以澄清为什么非成员运算符 * 不能与第一个 mul() 做同样的事情?编码矩阵乘法函数的正确方法是什么?

更新 3:(已解决) 感谢 jpalecek,我根据他的回答修改了我的代码。

转发声明:

template < typename T, size_t m, size_t n, typename _Prd, size_t _m, size_t _n> 
const Matrix<T,m,_n,_Prd> operator * (const Matrix<T,m,n,_Prd>& lhs, const Matrix<T,_m,_n,_Prd> & rhs) ;

朋友声明:

// here is tricky
template <typename U, size_t mm, size_t nn, typename _Prd2, size_t _m, size_t _n>
friend const Matrix<U,mm,_n,_Prd2> operator* (const Matrix<U,mm,nn,_Prd2>& lhs, const Matrix<U,_m,_n,_Prd2>& rhs) ;

实施:

template <typename U, size_t mm, size_t nn, typename _Prd2, size_t _m, size_t _n>
const Matrix<U,mm,_n,_Prd2> operator* (const Matrix<U,mm,nn,_Prd2>& lhs, const Matrix<U,_m,_n,_Prd2>& rhs) 
{
    return lhs.mul(rhs) ;
}

mul() 作为成员函数:

template <typename T, size_t m, size_t n, typename _Prd>
template<size_t _m, size_t _n>
Matrix<T,m,_n,_Prd> Matrix<T,m,n,_Prd>::mul(const Matrix<T,_m,_n,_Prd> & B) const 
{
    assert (n == _m) ;
    Matrix<T,m,_n,_Prd> result ;
    for (size_t j = 0 ; j < m ; ++j)
        for (size_t i = 0 ; i < _n ; ++ i)
            for (size_t k = 0 ; k < n ; ++ k) 
                result.at(j,i) += this->at(j,k) * B.at(k,i) ;
    return result ;
}

用法:

//test * operator, all work
Matrix<double,2,3> testmat8(10.0) ;
Matrix<double,3,4> testmat9(2.0) ;
Matrix<double,4,4> testmat11(3.0) ;
Matrix<double,2,4> testmat10 ;
testmat10 = testmat8 * testmat9 * testmat11;
cout <<testmat10<<endl ;
testmat10 = testmat8.mul(testmat9) ;
cout << testmat10 << endl ;

【问题讨论】:

  • 在你的声明中丢失template &lt;size_t _m, size_t _n&gt;,对于初学者。
  • @WhozCraig,谢谢,但我没有得到你的回答。你到底是什么意思?
  • 查看 icepacks 的答案。你的语法不正确。
  • @WhozCraig,你能告诉我如何纠正它吗?我还是不明白……

标签: c++ templates generics


【解决方案1】:

您的语法无效。您将模板参数化两次:

template <typename T, size_t m, size_t n, typename _Prd>
template <size_t _m, size_t _n>

这没有明确的含义。 template&lt;...&gt; 后面应该是 operator* 的正文/声明,而不是另一个 template&lt;...&gt;

另见此处:"too many template-parameter-lists" error when specializing a member function

【讨论】:

  • 你能把修改后的代码贴在这里吗,我不太明白你的答案,我之前一直在使用双模板声明,这很好。
  • 您可能应该将两个列表合并为一个。请参阅随附的链接。
  • 非常感谢您的回答,但是我的问题与附加的链接不同,它们只需要一个 void 函数,我的返回一个不同的模板类型。我根据您的建议修改了我的代码,它虽然可以编译,但是当我实际使用时它不起作用就像 Matrix test = (Matrix) A * (Matrix) B ;
【解决方案2】:

您面临的问题是您无法与函数的部分特化(这些不存在)或一系列特化成为朋友。所以它要么是一个函数的所有特化,要么是一个函数:

template <class T> class A;
template <class T, class U>
void operator*(A<T>, A<U>);

template <class T>
class A {
    template <class X, class U>
    friend void ::operator*(A<X>, A<U>);

将适用于所有专业化(您必须用 6 个参数替换参数列表),

  friend void ::operator*<>(A<T>, A<T>);

将意味着一种特定的专业化(这不是您想要的)。示例herehere

【讨论】:

  • 我很感激,jpalecek,正如你所说。这太棘手了。
猜你喜欢
  • 2021-06-23
  • 1970-01-01
  • 2021-05-18
  • 2011-06-07
  • 2010-11-20
  • 2011-05-08
相关资源
最近更新 更多