C++ 具名要求:可交换 (Swappable)

来自cppreference.com
< cpp‎ | named req


 
 
C++ 具名要求
 

std::swap 与用户定义 swap() 均可见的语境中,此类型的任何左值或右值能与某个其他类型的任何左值或右值,可以用非限定函数调用 swap() 来进行交换。

要求

若对于任意 U 类型的对象 u 和任意 T 类型的对象 t,满足以下情况,则类型 U 与类型 T 可交换:

表达式 要求 语义
#include <algorithm> // C++11 前

#include <utility> // C++11 起
swap(u, t);

调用后,t 的值是 u 在调用前保有的值,而 u 的值是 t 在调用前保有的值。 调用名为 swap() 的函数,它是在由实参依赖查找所找到的所有具有这个名字的函数,和定义于头文件 <algorithm> (C++11 前)<utility> (C++11 起) 中的两个 std::swap 模板中,由重载决议所找到的函数。
#include <algorithm> // C++11 前

#include <utility> // C++11 起
swap(t, u);

同上 同上

许多标准库函数(例如许多算法)期待其实参满足可交换 (Swappable) ,这意味着每当标准库进行交换时,都使用等价于 using std::swap; swap(t, u); 的写法。

典型的实现进行二者之一

1) 在外围命名空间中定义非成员 swap,若要求访问非公开数据成员,则它可转发到成员 swap
2) 于类中定义友元函数(此方法对于除 ADL 之外的名字查找隐藏了类特有的 swap

注解

标准库进行交换时是否实际包含 <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); // 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++ 标准。

缺陷报告 应用于 出版时的行为 正确行为
LWG 226 C++98 标准库如何使用 swap 不明确 澄清为使用 std:: 以及 ADL 所找到的 swap

参阅

检查一个类型的对象是否能与同类型或不同类型的对象交换
(类模板)
指定一个类型能进行交换,或两个类型能彼此交换
(概念)