Namespaces
Variants

C++ named requirements: Swappable

From cppreference.net
C++ named requirements

この型の任意の左辺値または右辺値は、修飾されていない関数呼び出し 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 が保持していた値となる。 実引数依存の名前探索 によって見つかったその名前のすべての関数と、ヘッダー <algorithm> (until C++11) <utility> (since C++11) で定義されている2つの std::swap テンプレートの中から、オーバーロード解決によって見つかった swap ( ) という名前の関数を呼び出す。
#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 を定義する(この方法は、ADL以外の名前探索からクラス固有のswapを隠蔽します)。

注記

<algorithm> (C++11以前) <utility> (C++11以降) が標準ライブラリ関数がswapを実行する際に実際にインクルードされるかどうかは未規定であるため、ユーザー提供の 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 適用対象 公開時の動作 正しい動作
LWG 226 C++98 swap の標準ライブラリでの使用方法が不明確であった std:: とADLで見つかった swap の両方を使用するように明確化

関連項目

ある型のオブジェクトが同じ型または異なる型のオブジェクトと交換可能かどうかをチェックする
(クラステンプレート)
型が交換可能であるか、または2つの型が互いに交換可能であることを指定する
(コンセプト)