As already was pointed to (The C++ 20 Standard, 9.7.1.2 Namespace member definitions)
3 If a friend declaration in a non-local class first declares a class,
function, class template or function template100 the friend is a
member of the innermost enclosing namespace.
So this friend function add is a member of the namespace Foo2. However it is invisible in the namespace Foo2 until a corresponding function declaration appears in the namespace Foo2. And can be found only due to the argument-dependent look-up.
namespace Foo2 {
class Bar {
public:
friend void add( Bar ) {}
};
//..
The name add from the namespace Foo1 would be hidden if you write before the function xxx
namespace Foo2 {
class Bar {
public:
friend void add( Bar ) {}
};
void add( Bar );
//...
That is if the friend function add will be redeclared in the enclosing namespace.
Within the function xxx
void xxx() {
int i = 0;
using namespace Foo1;
add( i ); // Is this an error or not?
subtract( i ); // This is an error due to name hiding
}
the compiler considers the name substract in the following order. At first it looks through the enclosing namespace that is the namespace Foo2. And this namespace has the declared name substract. So the process of searching stops. The overloaded function void substract( int ) is not found because due to the using directive it is considered as a member of the global namespace. That is of the namespace that enclose the namespace specified in the using directive and the namespace that contains the using directive.
You can consider it the following way (due to the using directibe)
// the global namespace
void subtract( int ) {}
namespace Foo2
{
class Bar {
public:
friend void add( Bar ) {}
};
void subtract( Bar ) {}
void xxx() {
int i = 0;
// using namespace Foo1;
add( i ); // Is this an error or not?
subtract( i ); // This is an error due to name hiding
}
}
Instead of the using directive you could use a using declarations to make the both functions from the namespace Foo1 visible in the function xxx.
For example
void xxx() {
int i = 0;
using Foo1::subtract, Foo1::add;
add( i ); // Is this an error or not?
subtract( i ); // This is an error due to name hiding
}