[c++] Operator overloading on class templates

I'm having some problems defining some operator overloads for template classes. Let's take this hypothetical class for example.

template <class T>
class MyClass {
  // ...
};
  • operator+=

    // In MyClass.h
    MyClass<T>& operator+=(const MyClass<T>& classObj);
    
    
    // In MyClass.cpp
    template <class T>
    MyClass<T>& MyClass<T>::operator+=(const MyClass<T>& classObj) {
      // ...
      return *this;
    }
    

    Results in this compiler error:

    no match for 'operator+=' in 'classObj2 += classObj1'
    
  • operator<<

    // In MyClass.h
    friend std::ostream& operator<<(std::ostream& out, const MyClass<T>& classObj);
    
    
    // In MyClass.cpp
    template <class T>
    std::ostream& operator<<(std::ostream& out, const MyClass<T>& classObj) {
        // ...
        return out;
    }
    

    Results in this compiler warning:

    friend declaration 'std::ostream& operator<<(std::ostream&, const MyClass<T>&)' declares a non-template function
    

What am I doing wrong here?

This question is related to c++ templates operator-overloading

The answer is


// In MyClass.h
MyClass<T>& operator+=(const MyClass<T>& classObj);


// In MyClass.cpp
template <class T>
MyClass<T>& MyClass<T>::operator+=(const MyClass<T>& classObj) {
  // ...
  return *this;
}

This is invalid for templates. The full source code of the operator must be in all translation units that it is used in. This typically means that the code is inline in the header.

Edit: Technically, according to the Standard, it is possible to export templates, however very few compilers support it. In addition, you CAN also do the above if the template is explicitly instantiated in MyClass.cpp for all types that are T- but in reality, that normally defies the point of a template.

More edit: I read through your code, and it needs some work, for example overloading operator[]. In addition, typically, I would make the dimensions part of the template parameters, allowing for the failure of + or += to be caught at compile-time, and allowing the type to be meaningfully stack allocated. Your exception class also needs to derive from std::exception. However, none of those involve compile-time errors, they're just not great code.


This helped me with the exact same problem.

Solution:

  1. Forward declare the friend function before the definition of the class itself. For example:

       template<typename T> class MyClass;  // pre-declare the template class itself
       template<typename T> std::ostream& operator<< (std::ostream& o, const MyClass <T>& x);
    
  2. Declare your friend function in your class with "<>" appended to the function name.

       friend std::ostream& operator<< <> (std::ostream& o, const Foo<T>& x);
    

This way works:

class A
{
    struct Wrap
    {
        A& a;
        Wrap(A& aa) aa(a) {}
        operator int() { return a.value; }
        operator std::string() { stringstream ss; ss << a.value; return ss.str(); } 
    }
    Wrap operator*() { return Wrap(*this); }
};

You need to say the following (since you befriend a whole template instead of just a specialization of it, in which case you would just need to add a <> after the operator<<):

template<typename T>
friend std::ostream& operator<<(std::ostream& out, const MyClass<T>& classObj);

Actually, there is no need to declare it as a friend unless it accesses private or protected members. Since you just get a warning, it appears your declaration of friendship is not a good idea. If you just want to declare a single specialization of it as a friend, you can do that like shown below, with a forward declaration of the template before your class, so that operator<< is regognized as a template.

// before class definition ...
template <class T>
class MyClass;

// note that this "T" is unrelated to the T of MyClass !
template<typename T>
std::ostream& operator<<(std::ostream& out, const MyClass<T>& classObj);

// in class definition ...
friend std::ostream& operator<< <>(std::ostream& out, const MyClass<T>& classObj);

Both the above and this way declare specializations of it as friends, but the first declares all specializations as friends, while the second only declares the specialization of operator<< as a friend whose T is equal to the T of the class granting friendship.

And in the other case, your declaration looks OK, but note that you cannot += a MyClass<T> to a MyClass<U> when T and U are different type with that declaration (unless you have an implicit conversion between those types). You can make your += a member template

// In MyClass.h
template<typename U>
MyClass<T>& operator+=(const MyClass<U>& classObj);


// In MyClass.cpp
template <class T> template<typename U>
MyClass<T>& MyClass<T>::operator+=(const MyClass<U>& classObj) {
  // ...
  return *this;
}

You must specify that the friend is a template function:

MyClass<T>& operator+=<>(const MyClass<T>& classObj);

See this C++ FAQ Lite answer for details.


Examples related to c++

Method Call Chaining; returning a pointer vs a reference? How can I tell if an algorithm is efficient? Difference between opening a file in binary vs text How can compare-and-swap be used for a wait-free mutual exclusion for any shared data structure? Install Qt on Ubuntu #include errors detected in vscode Cannot open include file: 'stdio.h' - Visual Studio Community 2017 - C++ Error How to fix the error "Windows SDK version 8.1" was not found? Visual Studio 2017 errors on standard headers How do I check if a Key is pressed on C++

Examples related to templates

*ngIf else if in template 'if' statement in jinja2 template How to create a link to another PHP page Flask raises TemplateNotFound error even though template file exists Application not picking up .css file (flask/python) Django: How can I call a view function from template? Angularjs Template Default Value if Binding Null / Undefined (With Filter) HTML email in outlook table width issue - content is wider than the specified table width How to redirect on another page and pass parameter in url from table? How to check for the type of a template parameter?

Examples related to operator-overloading

Operator overloading ==, !=, Equals operator << must take exactly one argument assignment operator overloading in c++ What are the basic rules and idioms for operator overloading? Operator overloading on class templates How to code a modulo (%) operator in C/C++/Obj-C that handles negative numbers How to override the [] operator in Python? Operator overloading in Java How to properly overload the << operator for an ostream? How do I overload the [] operator in C#