friend A f();
This line declares that the non-template function A f()
exists and is a friend of the class. This is not the same function as f<A>()
-- it's a completely new function.
friend B f();
This line declares another non-template function with the same name, but a different return type. You can't overload on the return type of a function, so this is forbidden.
Neither of these friend declarations refer to your template function, and in your second example the two friend declarations still don't refer to the previously-declared template function; they refer to some other non-template function, just like the friend declarations in your first example.
This is probably what you meant:
class A {
friend A f<A>();
};
class B {
friend B f<B>();
};
And, to fix your second example:
class A {
friend void f<A>(A);
};
class B {
friend void f<B>(B);
};