此页面中列出的具名要求,是 C++ 标准的规范性文本中使用的具名要求,用于定义标准库的期待。
某些具名要求在 C++20 中正在以概念语言特性进行形式化。在那之前,确保以满足这些要求的模板实参实例化标准库模板是程序员的重担。若不这么做,则可能导致非常复杂的编译器诊断。
C++ 具名要求: Swappable
在 std::swap 与用户定义 swap() 均可见的语境中,此类型的任何左值或右值能与某个其他类型的任何左值或右值,可以用非限定函数调用 swap() 来进行交换。
若对于任意 U 类型的对象 u 和任意 T 类型的对象 t,满足以下情况,则类型 U 与类型 T 可交换:
表达式 | 要求 | 语义 |
---|---|---|
#include <utility> using std::swap; | 调用后,t 的值是 u 在调用前保有的值,而 u 的值是 t 在调用前保有的值。 | 调用名为 swap() 的函数,它是在由实参依赖查找所找到的所有具有这个名字的函数,和定义于头文件 <utility> 中的两个 std::swap 模板中,由重载决议所找到的函数。 |
#include <utility> using std::swap; | 同上 | 同上 |
许多标准库函数(例如许多算法)期待其实参满足可交换 (Swappable) ,这意味着每当标准库进行交换时,都使用等价于 using std::swap; swap(t, u); 的写法。
典型的实现进行二者之一
1) 在外围命名空间中定义非成员 swap,若要求访问非公开数据成员,则它可转发到成员 swap
2) 于类中定义友元函数(此方法对于除 ADL 之外的名字查找隐藏了类特有的 swap)
标准库进行交换时是否实际包含 <utility> 是未指明的,因此用户提供的 swap() 不应当期待它已被包含。
C++ 具名要求: ValueSwappable
此类型的两个对象可以解引用,且在 std::swap 和用户定义 swap() 均可见的语境中,其结果值可以用无限定的函数调用 swap() 进行交换。
以下情况下,类型 T 为值可交换 (ValueSwappable) :
1) 类型 T
满足遗留迭代器 (LegacyIterator) 要求
2) 对任何 T
类型的可解引用对象 x
(即并非尾迭代器的值),*x
满足可交换 (Swappable) 要求。
许多标准库函数均期待其实参满足值可交换 (ValueSwappable) ,这意味着凡在标准库进行交换时,它都使用 using std::swap; swap(*iter1, *iter2); 的等价物。
#include <iostream>
#include <vector>
class IntVector
{
std::vector<int> v;
IntVector& operator=(IntVector) = delete; // 不可赋值
public:
IntVector(const std::vector<int> &t): v(t)
{
}
void swap(IntVector& other)
{
v.swap(other.v);
}
void printf()
{
for (int iV : v)
{
std::cout << iV << " ";
}
}
};
void swap(IntVector& v1, IntVector& v2)
{
v1.swap(v2);
}
int main()
{
IntVector v1({1, 2, 3, 4, 5});
IntVector v2({6, 7, 8, 9, 0});
std::cout << "v1: ";
v1.printf();
std::cout << std::endl;
std::cout << "v2: ";
v2.printf();
std::cout << std::endl;
// std::swap(v1, v2); // 编译器错误!std::swap 要求可移动赋值 (MoveAssignable)
std::iter_swap(&v1, &v2); // OK:标准库调用无限定的 swap()
std::cout << std::endl;
std::cout << "after iter_swap" << std::endl;
std::cout << std::endl;
std::cout << "v1: ";
v1.printf();
std::cout << std::endl;
std::cout << "v2: ";
v2.printf();
std::cout << std::endl;
IntVector* p1 = &v1;
IntVector* p2 = &v2; // IntVector* 为值可交换 (ValueSwappable)
std::iter_swap(p1, p2); // OK:iter_swap 要求值可交换 (ValueSwappable)
// std::swap(v1, v2); // 编译器错误!std::swap 要求可移动赋值 (MoveAssignable)
std::cout << std::endl;
std::cout << "after iter_swap" << std::endl;
std::cout << std::endl;
std::cout << "v1: ";
v1.printf();
std::cout << std::endl;
std::cout << "v2: ";
v2.printf();
std::cout << std::endl;
return 0;
}
v1: 1 2 3 4 5
v2: 6 7 8 9 0
after iter_swap
v1: 6 7 8 9 0
v2: 1 2 3 4 5
after iter_swap
v1: 1 2 3 4 5
v2: 6 7 8 9 0