1

我正在编写一个矩阵基类,并遇到了标题中的问题。

这里是我的报关表。

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

我在同一个类上遇到了另一个问题,当从原始返回不同的模板类型时,没有匹配的函数

更新

我根据下面的建议进行了修改,但它仍然不起作用。

前向声明:

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() 做同样的事情?什么是编码我的矩阵乘法函数的正确方法?

Update3:(已解决) 感谢 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 ;
4

2 回答 2

3

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

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

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

另请参见此处:专门化成员函数时出现“模板参数列表过多”错误

于 2012-11-22T06:26:45.340 回答
1

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

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>);

将意味着一个特定的专业化(这不是你想要的)。这里这里的例子。

于 2012-11-22T23:42:47.923 回答