1

I'm writing a matrix base class, and met the problem as the title.

Here is my declaration.

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

And friend declaration inside class.

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

And implementation:

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

However these don't compile, the error is:

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

I met another problem on the same class here no matching function when return different template type from the original

Update :

I modified according to the suggestions under, however it still doesn't work.

Forward declaration :

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

Friend declaration inside class:

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

Implementation :

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

But when I want to use it like this:

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

Error is:

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&)'

Still unsolved...

Update2:

To clarify my purpose I coded 3 work around. However not all of them work as expected.

//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 ;
}

And I call them in this way:

    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.

But what the answer I want is someone could clarify why the non-member operator * could not do the same as the first mul() ? And what is the proper way of coding my matrix multiplication function ?

Update3: (Solved) Thanks to jpalecek, I modified my code according to his answer.

Forward declaration:

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

Friend declaration:

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

Implementation:

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() as member 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>::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 ;
}

Usage:

//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 ;
Community
  • 1
  • 1
tomriddle_1234
  • 3,145
  • 6
  • 41
  • 71

2 Answers2

3

Your syntax is invalid. You're parametrizing the template twice:

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

This has no defined meaning. template<...> should be followed by the body/declaration of your operator*, not by another template<...>.

Also see here: "too many template-parameter-lists" error when specializing a member function

Community
  • 1
  • 1
SomeWittyUsername
  • 18,025
  • 3
  • 42
  • 85
  • Could you please paste modified code here, I didn't quite get your answer, I have been using double template declaration before which was fine. – tomriddle_1234 Nov 22 '12 at 06:30
  • 1
    You should probably unite both lists into one. See the attached link. – SomeWittyUsername Nov 22 '12 at 06:32
  • thanks so much for the answer, however my problem is different from the attached link, they just need a void function, my mine returns a different templated type. I modified my code according to your suggestion, it compiles though, but it doesn't work when I actually use is like Matrix test = (Matrix) A * (Matrix) B ; – tomriddle_1234 Nov 22 '12 at 22:35
1

The problem you are facing is that you cannot befriend a partial specialization of a function (these do not exist) or a family of specializations. So it's either all specializations of a function, or a single one:

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

would be for all specializations (you would have to replace the parameter list with your 6 arguments),

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

would mean the one specific specialization (that's not what you want). Examples here and here.

jpalecek
  • 47,058
  • 7
  • 102
  • 144