Namespaces
Variants

C++ named requirements: Swappable

From cppreference.net
C++ named requirements

该类型的任何左值或右值都可以与其他类型的任何左值或右值进行交换,通过在同时可见 std::swap 和用户自定义 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> (C++11 前) <utility> (C++11 起) 中定义的两个 std::swap 模板,通过重载决议调用名为 swap ( ) 的函数。
#include <algorithm> // until C++11

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

同上 同上

许多标准库函数(例如众多算法)要求其参数满足 可交换 条件,这意味着当标准库执行交换操作时,会采用等效于 using std:: swap ; swap ( t, u ) ; 的方式。

典型实现要么

1) 在封闭命名空间中定义一个非成员 swap 函数,若需访问非公有数据成员,可转发至成员 swap 实现。
2) 在类内定义 友元函数 (这种方法会隐藏特定类的 swap,使其仅能通过 ADL 进行名称查找)。

注释

未指定标准库函数执行交换时是否实际包含 <algorithm> (C++11 前) <utility> (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); // 正常:库调用非限定 swap()
    prn();
    std::ranges::swap(v1, v2); // 正常:库调用非限定 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++标准。

缺陷报告 应用于 发布时的行为 正确行为
LWG 226 C++98 标准库如何使用 swap 不够明确 明确说明同时使用 std:: 和 ADL 查找到的 swap

另请参阅

检查某类型的对象能否与相同或不同类型的对象进行交换
(类模板)
规定类型可交换或两个类型可相互交换
(概念)