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!
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);
};