The rule is that, when looking for a suitable function overload, both the current namespace and all namespaces of the argument type definitions are considered. This is called Argument Dependent Lookup (ADL).
So when you have this code:
::std::ostream& os = /* something */;
const ::bar::Foo& foo = /* something */;
os << foo;
The following namespaces are considered:
- The current namespace
- ::std, because os' type is defined there
- ::bar, because foo's type is defined there
So all three possibilities you named, will work and thus are 'good enough' on first glance.
However....
You are not allowed to define new functions in ::std, so you can't put your overloaded operator in that namespace. (You are allowed to specialize templates in ::std, but that's not what we are doing here)
Secondly, the "current namespace" may change, so if you put your function definition in that namespace, it might not always be found.
So in the end, the best place to put the overloaded operator is in the same namespace as Foo:
namespace bar
{
std::ostream& operator<<(std::ostream& os, const Foo& foo);
}