If we have a function in the global namespace and an overload with different argument types in another namespace, it seems that C++Builder compiler doesn't find the function from the global namespace.
namespace A
{
class a {
friend void swap(a& first, a& second) { }
};
}
class b {
friend void swap(b& first, b& second) { }
};
namespace C
{
class c {
A::a dataA;
b dataB;
friend void swap(c& first, c& second)
{
swap(first.dataA, second.dataA); // no problem
swap(first.dataB, second.dataB); // VC++12 compiles, C++Builder XE doesn't
}
friend void swap2(c& first, c& second) // no problem with a different name
{
swap(first.dataA, second.dataA);
swap(first.dataB, second.dataB);
}
};
}
C++Builder gives the following errors:
E2357 Reference initialized with 'b', needs lvalue of type 'c'
E2342 Type mismatch in parameter 'first' (wanted 'c &', got 'b')
Visual C++ 2012 compiles this without errors.
I have understood that the function in global namespace should be found even when there exists a function with the same name and different argument types.
Have I missed something, or is this a bug in C++Builder?
It looks like a compiler bug to me. In both cases, ADL should
kick in. In the first case, it looks in namespace A
,
including names in namespace A
that were only declared in
class a
, and finds A::swap
. In the second case, it looks in
the global namespace (since that is where b
is defined),
including names in the global namespace that were only declare
in class b
, and finds ::swap
.
Of course, it starts with unqualified name lookup, which will
only find C::swap in both cases. Apparently, C++Builder somehow
marks ::swap
as hidden in this case, and fails to consider it
in ADL. In the case of ADL, however, both the global namespace
and namespace A should be treated equally.
The full rules are in §3.4.2. It's pretty heavy going, but for simple cases like yours, the implications are clear.