Функция не найдена в глобальном пространстве имен, если есть перегрузка с различными типами аргументов

Если у нас есть функция в глобальном пространстве имен и перегрузка с другими типами аргументов в другом пространстве имен, то кажется, что компилятор C++Builder не находит функцию из глобального пространства имен.

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 выдает следующие ошибки:

E2357 Reference initialized with 'b', needs lvalue of type 'c'
E2342 Type mismatch in parameter 'first' (wanted 'c &', got 'b')

Visual C++ 2012 компилирует это без ошибок.

Я понял, что функция в глобальном пространстве имен должна быть найдена, даже если существует функция с тем же именем и разными типами аргументов.

Я что-то пропустил, или это ошибка в C++Builder?

2 ответа

Решение

Это похоже на ошибку компилятора для меня. В обоих случаях ADL должен сработать. В первом случае он выглядит в пространстве имен Aвключая имена в пространстве имен A которые были объявлены только в классе aи находит A::swap, Во втором случае он выглядит в глобальном пространстве имен (поскольку именно здесь b определяется), включая имена в глобальном пространстве имен, которые были объявлены только в классе bи находит ::swap,

Конечно, он начинается с поиска по неквалифицированному имени, в котором C::swap найдется только в обоих случаях. Судя по всему, C++Builder как-то отмечает ::swap как скрытый в этом случае, и не может рассмотреть его в ADL. Однако в случае ADL как глобальное пространство имен, так и пространство имен A должны обрабатываться одинаково.

Полные правила приведены в §3.4.2. Это довольно тяжело, но для простых случаев, подобных вашему, последствия очевидны.

Члены локальной области с тем же именем, что и у глобальной, всегда скрывают глобальную, поэтому называйте ее какA::a::swap(first.dataA, second.dataA);,

Другие вопросы по тегам