C++ 命名要求: Swappable
来自 cppreference.cn
此类型的任何左值或右值可以与某些其他类型的任何左值或右值交换,使用非限定函数调用 swap() 在 std::swap 和用户定义的 swap() 都可见的上下文中。
目录 (Contents) |
[编辑] 要求 (Requirements)
如果对于类型 U 的任何对象 u 和类型 T 的任何对象 t,类型 U 与类型 T 是可交换的:
表达式 (Expression) | 要求 (Requirements) | 语义 (Semantics) |
---|---|---|
#include <algorithm> // 直到 C++11 #include <utility> // 自 C++11 起 |
调用后,t 的值是调用前 u 持有的值,而 u 的值是调用前 t 持有的值。 |
调用名为 swap() 的函数,该函数通过重载解析在所有具有该名称的函数中找到,这些函数通过实参依赖查找 (argument-dependent lookup) 和在头文件 <algorithm>(直到 C++11)<utility>(自 C++11 起) 中定义的两个 std::swap 模板找到。 |
#include <algorithm> // 直到 C++11 #include <utility> // 自 C++11 起 |
相同 (Same) | 相同 (Same) |
许多标准库函数(例如,许多算法)期望它们的参数满足 Swappable,这意味着任何时候标准库执行交换时,它都使用等效于 using std::swap; swap(t, u);。
典型的实现方式是:
1) 在外围命名空间中定义一个非成员 (non-member) swap,如果需要访问非公共数据成员,该 swap 可能会转发到成员 (member) swap。
2) 在类内 (in-class) 定义一个 友元函数 (friend function)(这种方法将类特定的 swap 从名称查找中隐藏起来,除了 ADL 之外)。
[编辑] 注解 (Notes)
当标准库函数执行 swap 时,是否实际包含了 <algorithm>(直到 C++11)<utility>(自 C++11 起) 是未指定的,因此用户提供的 swap() 不应期望它被包含。
[编辑] 示例 (Example)
运行此代码
#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(); }
输出 (Output)
v1{{1, 1, 1, 1}}, v2{{2222, 2222}}; v1{{2222, 2222}}, v2{{1, 1, 1, 1}}; v1{{1, 1, 1, 1}}, v2{{2222, 2222}};
[编辑] 缺陷报告 (Defect reports)
以下行为变更缺陷报告被追溯应用于先前发布的 C++ 标准。
DR | 应用于 (Applied to) | 已发布行为 (Behavior as published) | 正确行为 (Correct behavior) |
---|---|---|---|
LWG 226 | C++98 | 标准库如何使用 swap 尚不清楚 |
澄清为同时使用 std:: 和 ADL 找到的 swap |
[编辑] 参见 (See also)
(C++17)(C++17)(C++17)(C++17) |
检查一个类型的对象是否可以与相同或不同类型的对象交换 (类模板) |
(C++20) |
指定一个类型可以被交换,或两个类型可以彼此交换 (概念) |