0

I have written a matrix class. I have overloaded the operator+, so that the user can write: matrix + 2. I would like the user to also write: 2 + matrix.

For the standard format (i.e. the object invoking 2) I have written a standard operator overloading function. It works.

template<typename T>
Matrix<T> Matrix<T>::operator+(const T& rhs) const
{
    Matrix result(rows, cols, 0.0);
    for (unsigned i = 0; i < rows; ++i)
    {
        for (unsigned j = 0; j < cols; ++j)
        {
            result(i,j) = (*this)(i, j) + rhs;
        }
    }
    return result;
}

Now for the other order (i.e. 2 + matrix), I have written the friend function:

// Friend Functions that allow the user to write expressions in a different order 
    template<typename T>
    friend Matrix<T> operator+(const T& type, const Matrix<T>& matrix);

and implementation as:

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

When I try to write 2 + matrix (in main()), I get some errors.

I have always had problems using friend functions with generic classes and frankly, I have never understood why it never works for me.

Could someone please explain what I am doing wrong here?

Errors I get:

IntelliSense: no operator "+" matches these operands operand types are: int + Matrix

Severity Code Description Project File Line Error C2244 'Matrix::operator +': unable to match function definition to an existing declaration

Ryan J. Shrott
  • 592
  • 1
  • 8
  • 26
  • @txtechhelp But a friend function is not a member function, so how can it use the scope resolution operator of Matrix – Ryan J. Shrott Aug 09 '15 at 03:52
  • Misread the code/issue .. apologies .. am re-reading the spec on friend/templates as your issue is a template deduction error (i.e. the compiler can't deduce the templated friend function properly) .. will post an answer/comment that's relevant .. – txtechhelp Aug 09 '15 at 03:58
  • If your friend function is declared in the `Matrix` class, can't you just do the following in the class: `friend Matrix operator+(const T& type, const Matrix& matrix) { return matrix + type; }` since it's a simple operation and could probably be inlined with some optimizations turned on if it's in the header .. ? – txtechhelp Aug 09 '15 at 04:20
  • WOW! Your extremely simple suggestion fixed the problem along with a large chain or errors! If you post your answer below, I will accept the answer as best. – Ryan J. Shrott Aug 09 '15 at 04:24
  • @txtechhelp Which optimizations? it still puzzles me that the .cpp file couldn't find the friend function. – Ryan J. Shrott Aug 09 '15 at 04:25
  • @txtechhelp https://cloudup.com/c0A8aZAQwD1 – Ryan J. Shrott Aug 09 '15 at 04:29
  • 1
    "possible" with optimizations (keyword possible since the compiler might decide to not inline it and make it a function call), but I believe `/O1` or `/OI` will do the extra analysis for the inline possibility .. and your matrix.cpp file can find the friend function, but due to how/why templates link across files, your main.cpp wouldn't find the proper linkage (which is why shoving it in the header works, because it can be deduced/linked directly in all files accessing it, so to speak).. – txtechhelp Aug 09 '15 at 04:35
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/86535/discussion-between-ryan-and-txtechhelp). – Ryan J. Shrott Aug 09 '15 at 04:37
  • @txtechhelp So would you suggest always using this method? Suppose my implementation was very long, so the inline function would not ideal. – Ryan J. Shrott Aug 09 '15 at 04:38
  • The inlining of the function is dependent on the compiler .. that is to say that just because the function is small and even if you have the `inline` keyword on the function, the compiler can still decide to not inline the function. As for always doing it this way; it really just depends on how you want to present your class and what you want to do .. you may not have a 'choice' but to do it this way (header definition and implementation) due to how the linkages work in C++ (linking, not compiling) .. so it just depends, but it's not uncommon to have 'long' functions in headers when needed – txtechhelp Aug 09 '15 at 04:45

2 Answers2

1

You can fix the problem simply by changing the member function to const.

template<typename T>
Matrix<T> Matrix<T>::operator+(const T& rhs) const
{
   ...
}
R Sahu
  • 204,454
  • 14
  • 159
  • 270
  • That definitely is correct, but it did not fix my problem. I still have: Severity Code Description Project File Line Error C2784 'std::_Vb_iterator<_Alloc> std::operator +(_Alloc::difference_type,std::_Vb_iterator<_Alloc>)': could not deduce template argument for 'std::_Vb_iterator<_Alloc>' from 'QS – Ryan J. Shrott Aug 09 '15 at 03:48
  • @Ryan, that seems to be a different problem. I am guessing it's got to do with the return type of the call `(*this)(i, j)` – R Sahu Aug 09 '15 at 04:08
  • It returns T&, which is exactly what I want. – Ryan J. Shrott Aug 09 '15 at 04:14
  • Do you also have a `const` version? You need a non-`const` version so you can use it as an lvalue. You need a `const` version so you can call it on `this`. – R Sahu Aug 09 '15 at 04:15
  • @R Sahu I have both implemented. – Ryan J. Shrott Aug 09 '15 at 04:18
  • Please post an [MCVE](http://stackoverflow.com/help/mcve). That will definitely be helpful. – R Sahu Aug 09 '15 at 04:19
1

It looks like it's just a template deduction error; that is to say that your compiler can't deduce the proper function based on the templated friend function.

Since your friend function is a simple function, you could just declare it in your class/header and the compiler should be able to deduce it properly (as well as possibly inline it if optimizations are turned on); just declare the friend function in your header like such:

friend Matrix operator+(const T& type, const Matrix& matrix)
{
    return matrix + type;
}

You don't need to specify the template keyword since it's within your template specialized class.

Hope that can help.

txtechhelp
  • 6,625
  • 1
  • 30
  • 39
  • This works and fixes the problem. I've still never successfully implemented a friend function in a generic class (with implementation in the .cpp file). Oh well. – Ryan J. Shrott Aug 09 '15 at 04:32