c++namespacesc++builderc++builder-xename-lookup

Function not found from global namespace if there's an overload with different argument types


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?


Solution

  • 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.