Since Test
is within namespace B
the compile sees the operator in that namespace and notes that it doesn't have a matching signature. It also attempts to find the operator in namespace A which contains the class but can't find it there either. Because there's already such an operator (with the wrong signature) in namespace B
it won't go and attempt to find one at global scope.
The reason it doesn't search for the global one is roughly as follows. I'm first going to quote the standard and then try to explain it.
From 3.4/1:
...Name lookup may associate more than
one declaration with a name if it
finds the name to be a function name;
the declarations are said to form a
set of overloaded functions (13.1).
Overload resolution (13.3) takes place
after name lookup has succeeded.
As I read this, when the compiler is trying to find a function (which your operators is in this context) it first tries to do name lookup to find the function first. Then next it tries to pick the right function from the set of overloads.
Now from 3.4.1/6:
A name used in the definition of a
function(26) that is a member of
namespace N (where, only for the
purpose of exposition, N could
represent the global scope) shall be
declared before its use in the block
in which it is used or in one of its
enclosing blocks (6.3) or, shall be
declared before its use in namespace N
or, if N is a nested namespace, shall
be declared before its use in one of
N’s enclosing namespaces.
Let's break this down. You're using the operator<<
in a namespace level function so this section applies. It's going to try to find that operator using the precedence in the described above. Your operator isn't declared in the current block or enclosing blocks (this is referring to nested {}
within your function). However the next part matches "...shall be declared before its use in namespace N...". There is in fact an operator<<
in the current namespace (B
) so it adds that operator to its list of matches. There aren't any more matches in B
, and because same-namespace scope is considered the best possible match-closeness, it won't look into any other scopes.
The reason it works when you put the operator into namespace A is that since the item being printed is a member of A
, that namespace is actually considered because it's included in the namespaces of the expression. Since namespace A
is considered it finds the appropriate match in that namespace and compiles correctly.
Now that it has a list of possible operators, it tries to do overload resolution on them. Unfortunately the one in found in namespace B is the only one it considers and it doesn't match the required arguments.
In general you should have the insertion operators in the same namespace as the class upon which it operates.
Test
innamespace A
, it compiles and executes correctly! – Coquina