名前空間
変種
操作

C++ 名前付き要件: Swappable

From cppreference.com
 
 
C++ 名前付き要件
 

この型の any lvalue または rvalue は、unqualified function call swap() を使用して、std::swap とユーザー定義の swap() の両方が可視であるコンテキストにおいて、他の型の any lvalue または rvalue と交換できます。

目次

[編集] 要件

型 U は型 T と swappable であるとは、任意のオブジェクト u (型 U) および任意のオブジェクト t (型 T) に対して、

Expression 要件 セマンティクス
#include <algorithm> // C++11 まで

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

呼び出し後、t の値は呼び出し前の u が保持していた値となり、u の値は呼び出し前の t が保持していた値となります。 名前が swap() である関数を呼び出します。この関数は、引数依存探索 (ADL) によって見つかるすべての関数と、ヘッダー <algorithm>(until C++11)<utility>(since C++11) で定義された 2 つの std::swap テンプレートの中からオーバーロード解決によって見つけられます。
#include <algorithm> // C++11 まで

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

同じ 同じ

多くの標準ライブラリ関数(例: 多くのアルゴリズム)は、引数が Swappable であることを期待します。これは、標準ライブラリがスワップを実行するたびに、using std::swap; swap(t, u); の等価物を使用することを意味します。

典型的な実装は次のいずれかです。

1) エンクロージング名前空間に非メンバースワップを定義します。これは、非公開データメンバーへのアクセスが必要な場合に、メンバースワップにフォワードすることができます。
2) クラス内にフレンド関数を定義します(このアプローチは、クラス固有のスワップを ADL 以外の名前探索から隠します)。

[編集] 注釈

標準ライブラリ関数がスワップを実行するときに <algorithm>(until C++11)<utility>(since C++11) が実際にインクルードされるかどうかは未指定であるため、ユーザー提供の swap() はそれがインクルードされることを期待すべきではありません。

[編集]

#include <iostream>
#include <vector>
 
struct IntVector
{
    std::vector<int> v;
 
    IntVector& operator=(IntVector) = delete; // not assignable
 
    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); // Compiler error! std::swap requires MoveAssignable
    prn();
    std::iter_swap(&v1, &v2); // OK: library calls unqualified swap()
    prn();
    std::ranges::swap(v1, v2); // OK: library calls unqualified 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つの型が互いに交換可能であることを規定する
(コンセプト) [編集]
English 日本語 中文(简体) 中文(繁體)