C++ 命名要求: 可交换
来自 cppreference.com
此类型的任何左值或右值都可以使用非限定函数调用 swap() 在 std::swap 和用户定义的 swap() 均可见的上下文中与其他类型的任何左值或右值交换。
内容 |
[编辑] 要求
如果类型 U 与类型 T 可交换,则对于类型 U 的任何对象 u 和类型 T 的任何对象 t,
表达式 | 要求 | 语义 |
---|---|---|
#include <algorithm> // C++11 之前 #include <utility> // C++11 之后 |
调用后,t 的值为调用前 u 所持有的值,而 u 的值为调用前 t 所持有的值。 |
调用通过重载解析在通过 依赖于参数的查找 找到的所有具有该名称的函数以及在头文件 <algorithm>(C++11 之前)<utility>(C++11 之后) 中定义的两个 std::swap 模板中找到的名为 swap() 的函数。 |
#include <algorithm> // C++11 之前 #include <utility> // C++11 之后 |
相同 | 相同 |
许多标准库函数(例如,许多算法)期望其参数满足 可交换,这意味着标准库执行交换时,它使用与 using std::swap; swap(t, u); 等效的操作。
典型的实现方法是:
1) 在封闭的命名空间中定义一个非成员交换函数,它可能转发到成员交换函数(如果需要访问非公共数据成员)。
2) 在类中定义一个 友元函数(此方法将特定于类的交换函数隐藏在除了 ADL 之外的名称查找之外)。
[编辑] 备注
未指定标准库函数执行交换时是否实际包含了 <algorithm>(C++11 之前)<utility>(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 |
[编辑] 另请参阅
(C++17)(C++17)(C++17)(C++17) |
检查类型的对象是否可以与相同或不同类型的对象交换 (类模板) |
(C++20) |
指定类型是否可以交换或两个类型是否可以相互交换 (概念) |