Because you're calling it and it has no definition!
This
template<typename T, typename U>
class A<T, U>::B {
friend bool operator==(const B& b1, const B& b2);
};
is a declaration of a non-template friend function of A<T,U>::B
class.
It matches the call (b1 == b2)
just as well as the template operator you define further down but it is preferred because it is a non-template.
GCC even gives a warning with -Wnon-template-friend
warning: friend declaration 'bool operator==(const A::B&, const A::B&)' declares a non-template function [-Wnon-template-friend]
note: (if this is not what you intended, make sure the function template has already been declared and add <> after the function name here)
To fix, it provide the definition
template<typename T, typename U>
class A<T, U>::B {
friend bool operator==(const B& b1, const B& b2) {
return true;
}
};
and get rid of the templated operator OR keep only the template one.