2
template<typename T>
class Matrix
{

    template<typename U>
    friend
    Matrix<U> operator+(const Matrix<U>& a, const Matrix<U>& b);


protected:

    size_t _m, _n;
    T *_alloc;
};

template<typename U>
Matrix<U> operator+(const Matrix<U>& a, const Matrix<U>& b)
{
    if(a._m == b._m && a._n == b._n)
    {
        Matrix<U> ret(a._m, a._n);

        // ...

        return ret;
    }
    else
    {
        throw "Matrix dimension mismatch error";
    }
}

I've overloaded operator+ before without problem using non-template classes. Here I'm using a template class.

Matrix<U> Matrix<U>::operator+(const Matrix<U>&, const Matrix<U>&) must take either zero or one argument.

It appears that the compiler is ignoring the friend keyword.

I also tried

friend
template<typename U>
Matrix<U> operator+(const Matrix<U>& a, const Matrix<U>& b);

But this gives me a different compiler error.

expected unqualified-id before 'template'

How can I overload operator+ with template classes?

1

3 Answers 3

4

You can overload the + operator using a member function or a non-member function.

When the operator is overloaded using a member function, the LHS of the operator is the object on which the function will be called and RHS of the operator is the argument to the function. Hence, the only argument to the member function will be the RHS.

When the operator is overloaded using a non-member function, the LHS of the operator is the first argument of the to the function and RHS of the operator is the second argument to the function.

Member function

template<typename T>
class Matrix
{
  Matrix operator+(const Matrix& rhs) const {
    ...
  }
};

If you want to implement it outside the class definition, you can use:

template<typename T>
  Matrix<T> Matrix<T>::operator+(const Matrix& rhs) const {
    ...
  }

Non-member function

template<typename T>
class Matrix
{
  Matrix operator+(const Matrix& lhs, const Matrix& rhs) {
    ...
  }
};

If you want to implement it outside the class definition, you need to add some forward declaration code:

// Forward declare the class template
template <typename T> class Matrix;

// Declare the function
template <typename T> Matrix<T> operator+(const Matrix<T>& lhs, const Matrix<T>& rhs);

// Declare the friend in the class definition
template <typename T>
class Matrix
{
   friend Matrix operator+<T>(const Matrix& lhs, const Matrix& rhs);
   //                     ^^^^ 
   // This makes operator+<int> a friend of Matrix<int>, not a friend
   // of Matrix<double>
};

and then implement the function

template <typename T> Matrix<T> operator+(const Matrix<T>& lhs, const Matrix<T>& rhs)
{
    ...
}

With this setup, oprator+<int> is a friend of Matrix<int> only, not a friend of Matrix<double>.

If you use

template <typename U>
friend
Matrix<U> operator+(const Matrix<U>& a, const Matrix<U>& b);

then, all instantiations of operator+ are friends of all instantiations of Matrix, which you don't need.

Update

Sample working code:

#include <iostream>
 
// Forward declare the class template
template<typename T> class Matrix;

// Declare the function
template <typename T> Matrix<T> operator+(const Matrix<T>& lhs, const Matrix<T>& rhs);

// Declare the friend in the class definition
template <typename T>
class Matrix
{
   friend Matrix operator+<T>(const Matrix& lhs, const Matrix& rhs);
   //                     ^^^^ 
   // This makes operator+<int> a friend of Matrix<int>, not a friend
   // of Matrix<double>
};

template <typename T> Matrix<T> operator+(const Matrix<T>& lhs, const Matrix<T>& rhs)
{
   return Matrix<T>{};
}

int main()
{
   Matrix<int> a;
   Matrix<int> b;
   Matrix<int> c = a + b;
}
Sign up to request clarification or add additional context in comments.

6 Comments

My forward declaration template<typename T> Matrix<T> gives the error error: Matrix does not name a type
Sorry, that should be just Matrix.
Still get the same error. Matrix does not name a type
Compiler is gcc 5.2.1, compiling with --std=c++11
@user3728501, I had couple of errors in the code. It fixed now. The update contains working code.
|
2

First, let me advise overloading += instead, then write + in terms of +=. Second, the friend shouldn't be a template typically.

template<typename T>
class Matrix
{
  friend Matrix operator+(Matrix a, const Matrix& b) {
    a += b;
    return std::move(a);
  }
  friend Matrix& operator+=(Matrix& a, const Matrix& b) {
    a.increase_by(b);
    return a;
  }
protected:
  void increase_by( const Matrix& other );

  size_t _m = 0
  size_t _n = 0;
  std::vector<T> _alloc;
};

template<class T>
void Matrix<T>::increase_by(const Matrix<T>& other) {
  if(this->_m == other._m && this->_n == other._n) {
    for (auto i = 0; i < _m*_n; ++i) {
      _alloc[i] += other._alloc[i];
    }
    // ...
  } else {
    throw "Matrix dimension mismatch error";
  }
}

Note that the above, with efficient move, will give you reasonably efficient a+b+c+d+e, as the lhs is created once and repeatedly moved.

5 Comments

return std::move(a); Why the move? The returned value is an rvalue anyways.
@BaummitAugen RVO cannot occur, the explicit move reminds me.
Why is that? Why can't auto c = a + b; for matrices a and b not trigger RVO without the move?
@BaummitAugen You cannot RVO from a function argument. a is a function argument of operator+. So I cannot RVO from a into operator+'s return value. I take the function argument a by-value to allow outsiders to elide into the object I return, which makes Matrix<int> x = a+b+c+d+e; very efficient. I consider the lack of full RVO acceptable, as moving a heap-allocated matrix type is pretty cheap.
Thanks, I did not know that. For those who don't know either, this is why.
0

Solution: Don't explicitly declare templates, they are automatically generated. Perhaps someone can explain why in more detail?

friend
Matrix operator+(const Matrix& a, const Matrix& b)
{
    if(a._m == b._m && a._n == b._n)
    {
        Matrix ret(a._m, a._n);

        return ret;
    }
    else
    {
        throw "Matrix dimension mismatch error";
    }
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.