Search code examples
c++c++11templatesoperator-overloadingfriend

How to define friend function templates of a class template for the purpose of operator overloading


I'm trying to get a friend function inside a templated class to compile, but the error message and warning I do not understand. I've made a demonstration of the issue. The error I'm getting is:

prog.cpp:8:57: error: non-class, non-variable partial specialization C operator+(const B& lhs, const C& rhs);

prog.cpp:15:59: warning: friend declaration 'C operator+(const B&, const C&)' declares a non-template function [-Wnon-template-friend] friend C operator+(const B& lhs, const C& rhs);

prog.cpp:15:59: note: (if this is not what you intended, make sure the function template has already been declared and add <> after the function name here)

#include <iostream>
using namespace std;

template<typename A, typename B>
class C;

template<typename A, typename B>
C<A, B> operator+<A, B>(const B& lhs, const C<A, B>& rhs);

template<typename A, typename B>
struct C
{
    A val_;
    C operator+(const C& other) const;
    friend C<A, B> operator+(const B& lhs, const C<A, B>& rhs);
};

template<typename A, typename B>
C<A, B> C<A, B>::operator+(const C<A, B>& other) const
{
    C<A, B> c;
    c.val_ = this->val_ + other.val_;
    return c;
}

template<typename A, typename B>
 C<A, B> operator+(const B& lhs, const C<A, B>& rhs)
{
    C<A, B> c;
    c.val_ = lhs + rhs.val_;
    return c;
}

int main() 
{
    C<string, char> c0,c1;
    c0.val_ = " C0 ";
    c1.val_ = " C1 ";
    cout << "Stuct:" << (c0 + c1).val_ << '\n';
    cout << "Friend:" << ('~' + c1).val_ << endl;
    return 0;
}

Solution

  • This declaration:

    template<typename A, typename B>
    C<A, B> operator+<A, B>(const B& lhs, const C<A, B>& rhs);
    

    ...is wrong because of the <A,B> between operator+ and (, I don't really know what you wanted to do here. You would use this form if you were to specialize a templated operator+, but you are not here, you are overloading one.

    This declaration should be:

    template<typename A, typename B>
    C<A, B> operator+ (const B& lhs, const C<A, B>& rhs);
    

    Then you should explicitely specify in your friend declaration that you want a specialized version by writting:

    friend C<A,B> operator+<>(const B& lhs, const C<A,B>& rhs);
    

    You need to put this before your operator+, otherwize the compiler will think this is a specialization of a non-templated function.

    Anyway, if you have no real reason to put your code outside the C class, I would go @Jarod42 solution.


    Your whole code should look like this:

    // Declaration of struct C with delayed definition
    template <typename A, typename B>
    struct C;
    
    // Initial declaration of templated operator+
    template <typename A, typename B>
    C<A, B> operator+ (const B&, const C<A, B>&);
    
    // Definition of C
    template <typename A, typename B>
    struct C {
    
        friend C operator+<> (const B&, const C&);
    
        // This must be AFTER the templated operator+
        C operator+ (const C&) const;
    };
    
    template<typename A, typename B>
    C<A, B> C<A, B>::operator+(const C<A, B>& other) const {
    
    }
    
    template<typename A, typename B>
    C<A, B> operator+(const B& lhs, const C<A, B>& rhs) {
    
    }