Namespaces
Variants

C++ named requirements: Swappable

From cppreference.net
C++ named requirements

Любое lvalue или rvalue этого типа может быть обменено с любым lvalue или rvalue другого типа, используя неквалифицированный вызов функции swap ( ) в контексте, где видны как std::swap , так и пользовательские swap ( ) .

Содержание

Требования

Тип U является заменяемым с типом T, если для любого объекта u типа U и любого объекта t типа T,

Выражение Требования Семантика
#include <algorithm> // until C++11

#include <utility> // since C++11
using std:: swap ;
swap ( u, t ) ;

После вызова значение t равно значению, которое хранилось в u до вызова, а значение u равно значению, которое хранилось в t до вызова. Вызывает функцию с именем swap ( ) найденную с помощью разрешения перегрузки среди всех функций с этим именем, которые найдены с помощью поиска, зависимого от аргументов и двух шаблонов std::swap определённых в заголовке <algorithm> (до C++11) <utility> (начиная с C++11) .
#include <algorithm> // until C++11

#include <utility> // since C++11
using std:: swap ;
swap ( t, u ) ;

То же То же

Многие функции стандартной библиотеки (например, многие алгоритмы) ожидают, что их аргументы удовлетворяют требованиям Swappable , что означает, что когда стандартная библиотека выполняет обмен, она использует эквивалент using std:: swap ; swap ( t, u ) ; .

Типичные реализации либо

1) Определите нечленную функцию swap во внешнем пространстве имен, которая может перенаправлять на членскую функцию swap, если требуется доступ к непубличным членам данных.
2) Определите friend function внутри класса (этот подход скрывает специализированный swap класса от поиска имен, за исключением ADL).

Примечания

Не указано, включается ли на самом деле <algorithm> (until C++11) <utility> (since C++11) при выполнении обмена стандартными библиотечными функциями, поэтому пользовательская реализация swap ( ) не должна рассчитывать на её включение.

Пример

#include <iostream>
#include <vector>
struct IntVector
{
    std::vector<int> v;
    IntVector& operator=(IntVector) = delete; // не присваиваемый
    void swap(IntVector& other)
    {
        v.swap(other.v);
    }
    void operator()(auto rem, auto term = " ")
    {
        std::cout << rem << "{{";
        for (int n{}; int e : v)
            std::cout << (n++ ? ", " : "") << e;
        std::cout << "}}" << term;
    }
};
void swap(IntVector& v1, IntVector& v2)
{
    v1.swap(v2);
}
int main()
{
    IntVector v1{{1, 1, 1, 1}}, v2{{2222, 2222}};
    auto prn = [&]{ v1("v1", ", "), v2("v2", ";\n"); };
//  std::swap(v1, v2); // Ошибка компиляции! std::swap требует MoveAssignable
    prn();
    std::iter_swap(&v1, &v2); // OK: библиотека вызывает неквалифицированный swap()
    prn();
    std::ranges::swap(v1, v2); // OK: библиотека вызывает неквалифицированный swap()
    prn();
}

Вывод:

v1{{1, 1, 1, 1}}, v2{{2222, 2222}};
v1{{2222, 2222}}, v2{{1, 1, 1, 1}};
v1{{1, 1, 1, 1}}, v2{{2222, 2222}};

Отчёты о дефектах

Следующие отчеты об изменениях в поведении, содержащие описания дефектов, были применены ретроактивно к ранее опубликованным стандартам C++.

DR Applied to Behavior as published Correct behavior
LWG 226 C++98 it was unclear how the standard library uses swap clarified to use both std:: and ADL-found swap

Смотрите также

проверяет, можно ли обменивать объекты одного типа с объектами того же или другого типа
(шаблон класса)
указывает, что тип можно обменивать или что два типа можно обменивать друг с другом
(концепт)