Daily bit(e) C++. Корректный вызов std::swap
Daily bit(e) C++ 62, корректный вызов std::swap для пользовательских типов во избежание проблем с ADL (argument-dependent lookup).

При использовании std::swap с пользовательскими типами необходимо быть осторожным с последствиями поиска, зависимого от аргументов (ADL).
Квалифицированный вызов std::swap всегда вызовет реализацию по умолчанию. Неквалифицированный вызов может с помощью ADL найти пользовательскую реализацию, но не увидит реализацию по умолчанию.
Поэтому для правильного вызова std::swap необходимо сначала переместить реализацию по умолчанию в локальную область видимости, и только затем выполнить неквалифицированный вызов.
В качестве альтернативы, в C++20 квалифицированный вызов std::ranges::swap всегда будет выполнять правильные действия.
#include <algorithm>
namespace MyNamespace {
struct MyClass
{
// Использовать встроенную дружескую функцию, чтобы
// реализовать пользовательский swap.
friend void swap(MyClass&, MyClass&) {}
};
struct MyOtherClass {};
}
// Обратите внимание, что объявление с именем swap,
// не являющееся функцией, в глобальной области видимости
// будет обнаружено при неквалифицированном поиске и
// предотвратит ADL.
// constexpr auto swap = "Hello!";
MyNamespace::MyClass a, b;
MyNamespace::MyOtherClass x, y;
// Полностью квалифицированный вызов всегда вызывает std::swap
std::swap(a,b); // вызывает std::swap
std::swap(x,y); // вызывает std::swap
// Нет подходящего swap для MyOtherClass.
swap(a,b); // вызывает MyNamespace::swap
// swap(x,y); // не скомпилируется
// Вытягиваем std::swap в качестве дефолтного в локальную
// область видимости:
{
using std::swap;
swap(a,b); // вызывает MyNamespace::swap
swap(x,y); // вызывает std::swap
}
// std::ranges::swap из C++20 делает это правильно:
std::ranges::swap(a,b); // вызывает MyNamespace::swap
std::ranges::swap(x,y); // дефолтный swap
