Функция не найдена в глобальном пространстве имен, если есть перегрузка с различными типами аргументов
Если у нас есть функция в глобальном пространстве имен и перегрузка с другими типами аргументов в другом пространстве имен, то кажется, что компилятор 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);
,