Overloading + Operator With Templates

10,615

Solution 1

In order to befriend a template, I think you'll need to declare that template before the class definition in which you want to befriend it. However, for this declaration to compile, you'll need to forward-declare the class template. So this should work:

template<typename T> 
class vec;

template<typename T> 
vec<T> operator + (vec<T>, const vec<T>&);

template<typename T> 
class vec{
public:
    friend vec<T> operator +<T> (vec<T>, const vec<T>&);
// ...

This befriends a specific instance of the operator+() function template, namely operator+<T>. (You can also befriend all instances of a template:

// no forward declarations necessary

template<typename T>
class some_class {
  template<typename U>
  friend void f(vec<U>&);
  // ... 
};

However, that's less often useful than the other one.)

Edit: A comment by David got me thinking (should've done this from the beginning!) and that lead to the discovery that the friend declaration is unnecessary. Your operator+ is only using one public member function of vec (operator+=) and thus doesn't need to be a friend of the class. So the above would simplify to

template<typename T> 
class vec{
public:
    // ...
};

template<typename T> 
vec<T> operator + (vec<T> a, const vec<T>& b){
    a += b;
    return a;
}

Here's a few more notes:

  • operator+() (which you nicely implemented on top of operator+=(), BTW) should take its left argument per copy.
  • Don't declare functions as inline, define them so.
  • Have operator+=() return a non-const reference, because everybody expects f(m1+=m2) to work even if f() takes its argument as a non-const reference.
  • Inside of a class template, in most places you can omit the template parameter list when refering to the class. So you can say vec& operator += (const vec&);. (You cannot do this outside of the template, though - for example, when defining that operator outside of the class.)
  • A std::vector's index type is spelled std::vector<blah>::size_type, not unsigned short.

Solution 2

The return type here:

inline friend vec<T> operator + (const vec<T>&, const vec<T>&);

Does not match here:

template<typename T> 
    vec<T>& operator + (const vec<T>& a, const vec<T>& b){
        vec<T> product = a;
        product += b;

        return product;
    } // Addition.
Share:
10,615
Admin
Author by

Admin

Updated on June 04, 2022

Comments

  • Admin
    Admin almost 2 years

    Hey, I'm getting a linker error LNK2019: unresolved external symbol when trying to use an overloaded + operator. I'll show you snip-its from the class, and how I'm using it in main. If you need to see more, let me know, I'm just going to try and keep things concise.

    /** vec.h **/
    #ifndef __VEC_H_
    #define __VEC_H_
    
    #include <iostream>
    #include <vector>
    
    namespace xoor{
    
        template<typename T> 
        class vec{
    
        public:
            inline friend vec<T> operator + (const vec<T>&, const vec<T>&);
            inline const vec<T>& operator += (const vec<T>&);
    
        private:
            std::vector<T> m_index;
        }; // Vec.
    
    
        template<typename T> 
        vec<T>& operator + (const vec<T>& a, const vec<T>& b){
            vec<T> product = a;
            product += b;
    
            return product;
        } // Addition.
    
        template<typename T> 
        const vec<T>& vec<T>::operator += (const vec<T>& v){
            for (unsigned short i =0; i < m_index.size(); ++i){
                if (i >= v.size())
                    break;
                m_index[i] += v.getIndex()[i];
            }
    
            return * this;
        } // Addition Compound.
    
    
    } // xoor
    
    #endif // __VEC_H_
    

    Note that I've got [] overloaded as well, so I'm just accessing parts of m_index with it. getIndex() just returns m_index. And size() returns m_index.size()

    /** main.cpp **/
    
    #include <iostream>
    #include "vec.h"
    
    void testHook();
    
    int main(){
        testHook();
        system("PAUSE");
        return 0;
    }
    
    void testHook(){
        using namespace xoor;
        vec<double> vA(3); // passing 3 for 3 elements
        vec<double> vB(3);
    
        // v + v
        std::cout << "\n\tA + B = ";
        vec<double> vAB(3);
        vAB = vA + vB; // PRODUCES THE LNK2019
        vAB.print(std::cout); // Outputs the vec class to the console.
    }
    

    Error Message:

    Error   1   error LNK2019: unresolved external symbol "class xoor::vec<double> __cdecl xoor::operator+(class xoor::vec<double> const &,class xoor::vec<double> const &)" (??Hxoor@@YA?AV?$vec@N@0@ABV10@0@Z) referenced in function "void __cdecl testHook(void)" (?testHook@@YAXXZ)    main.obj
    

    Update:

    The following is now directly above the class definition. I continue to get the same linker error, as described above.

        template<typename T> 
        class vec;
    
        template<typename T> 
        vec<T> operator + (const vec<T>&, const vec<T>&); 
    

    Update 2: Solution.

    The above update is incorrect. sbi's solution did work, I just failed to template the operator as follows.

        template<typename T> 
        vec<T> operator +<T> (const vec<T>&, const vec<T>&); 
    

    sbi, and david were discussing why I was using friends in the first place. Initially I was using them, because you can not pass two parameters to an overloaded binary operator such as +, and immediate sought after friends as the solution. As it turns out, you can still use the binary operator quite easily with a single parameter. Here is the final solution.

    // ...
    template<typename T> 
    class vec{
        public:
        const vec<T> operator + (const vec<T>&, const vec<T>&)const;
        // ...
    
    }; // Vec.
    
    template<typename T> 
    const vec<T> vec<T>::operator + (const vec<T>& v)const{
        matrix<T> product = *this;
        vec(product += v);
    } // Addition.
    

    Also, for anyone else reading this, its worth while to check out sbi's notes at the bottom of his answer. There are some things I've been doing that are superfluous.

    Thanks for the help everyone. Happy coding.