c++templatesoperator-overloadingfriend

Must a template friend operator overload precede a member function overload of the same operator?


Does anybody know why this compiles:

template<typename T>
class Foo;

template<typename T>
bool operator==(const T& l, const Foo<T>& r); 

template<typename T>
class Foo 
{
public:
    Foo();
    ~Foo();

    friend bool operator== <> (const T& l, const Foo<T>& r); 

    bool operator==(const Foo<T>& r);
};

But this does not (only difference is order of member vs friend operator==):

template<typename T>
class Foo;

template<typename T>
bool operator==(const T& l, const Foo<T>& r); 

template<typename T>
class Foo 
{
public:
    Foo();
    ~Foo();

    bool operator==(const Foo<T>& r);

    friend bool operator== <> (const T& l, const Foo<T>& r); 
};

I was banging my head against the second case, with an "error: declaration of ‘operator==’ as non-function" at the friend line. I finally decided there must be something wrong before the friend declaration, so I tried moving it up in the code to see if I could get a different error. Lo and behold, when I moved it above the member declaration, everything worked!


Solution

  • It's because after declaring a member operator== in the scope of the class, the name operator== will refer to that instead of the global template.

    I'm not sure that's the correct behaviour (might be a compiler bug, may also fall foul of https://stackoverflow.com/a/15538759/5754656), but what's happening is that operator== is parsed as a non-template, so the next < is a less than sign rather than part of a template-id.

    Qualifying it so that the non-member operator== is found instead fixes this:

    template<typename T>
    class Foo 
    {
    public:
        Foo();
        ~Foo();
    
        bool operator==(const Foo<T>& r);
    
        //friend bool operator== <> (const T& l, const Foo<T>& r);
        friend bool ::operator== <> (const T& l, const Foo<T>& r);
    };