C++ 命名要求: Swappable (可交換)
來自 cppreference.com
此型別的任何左值或右值都可以與某些其他型別的任何左值或右值交換,透過在 std::swap 和使用者定義的 swap() 都可見的上下文中,進行非限定函式呼叫 swap()。
目錄 |
[編輯] 要求
如果型別 U 的任何物件 u 和型別 T 的任何物件 t,滿足以下條件,則型別 U 與型別 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 起 |
相同 | 相同 |
許多標準庫函式(例如,許多演算法)都期望其引數滿足 Swappable,這意味著每當標準庫執行交換時,它都會使用等同於 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; // 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++ 標準。
缺陷報告 | 應用於 | 釋出時的行為 | 正確的行為 |
---|---|---|---|
LWG 226 | C++98 | 不清楚標準庫如何使用 swap |
澄清為同時使用 std:: 和透過 ADL 找到的 swap |
[編輯] 另見
(C++17)(C++17)(C++17)(C++17) |
檢查一種型別的物件是否可以與相同或不同型別的物件進行交換 (類模板) |
(C++20) |
指定型別可以被交換,或者兩種型別可以互相交換 (概念) |