比较运算符
比较参数。
运算符名 | 语法 | 可重载 | 原型示例(对 class T ) | |
---|---|---|---|---|
作为成员函数 | 作为自由(命名空间)函数 | |||
等于 | a == b
|
是 | bool T::operator ==(const T2 &b) const; | bool operator ==(const T &a, const T2 &b); |
不等于 | a != b
|
是 | bool T::operator !=(const T2 &b) const; | bool operator !=(const T &a, const T2 &b); |
小于 | a < b
|
是 | bool T::operator <(const T2 &b) const; | bool operator <(const T &a, const T2 &b); |
大于 | a > b
|
是 | bool T::operator >(const T2 &b) const; | bool operator >(const T &a, const T2 &b); |
小于或等于 | a <= b
|
是 | bool T::operator <=(const T2 &b) const; | bool operator <=(const T &a, const T2 &b); |
大于或等于 | a >= b
|
是 | bool T::operator >=(const T2 &b) const; | bool operator >=(const T &a, const T2 &b); |
三路比较(C++20) | a <=> b
|
是 | /*see description*/ T::operator <=>(const T2 &b) const; | /*see description*/ operator <=>(const T &a, const T2 &b); |
|
目录 |
[编辑] 双路比较
双路比较运算符拥有形式
lhs < rhs
|
(1) | ||||||||
lhs > rhs
|
(2) | ||||||||
lhs <= rhs
|
(3) | ||||||||
lhs >= rhs
|
(4) | ||||||||
lhs == rhs
|
(5) | ||||||||
lhs != rhs
|
(6) | ||||||||
true
,否则返回 false
。true
,否则返回 false
。true
,否则返回 false
。true
,否则返回 false
。true
,否则返回 false
。true
,否则返回 false
。所有情况下,对于内建运算符, lhs 和 rhs 必须拥有下列之一
- 算术或枚举类型(见后述算术比较运算符)
- 指针类型(见下方指针比较运算符)
任何情况下,结果为 bool
纯右值。
[编辑] 算术比较运算符
若运算数拥有算术或枚举类型(有作用域或无作用域),则在两个运算数上遵循算术运算符的规则进行通常算术转换。比较转换后的值:
[编辑] 示例
#include <iostream> int main() { std::cout << std::boolalpha; int n = -1; int n2 = 1; std::cout << " -1 == 1? " << (n == n2) << '\n' << "Comparing two signed values:\n" << " -1 < 1? " << (n < n2) << '\n' << " -1 > 1? " << (n > n2) << '\n'; unsigned int u = 1; std::cout << "Comparing signed and unsigned:\n" << " -1 < 1? " << (n < u) << '\n' << " -1 > 1? " << (n > u) << '\n'; unsigned char uc = 1; std::cout << "Comparing signed and smaller unsigned:\n" << " -1 < 1? " << (n < uc) << '\n' << " -1 > 1? " << (n > uc) << '\n'; }
输出:
-1 == 1? false Comparing two signed values: -1 < 1? true -1 > 1? false Comparing signed and unsigned: -1 < 1? false -1 > 1? true Comparing signed and smaller unsigned: -1 < 1? true -1 > 1? false
[编辑] 指针比较运算符
比较运算符能用于比较二个指针(或指向成员指针,仅对于 operator== 和 operator!= ),或一个(指向成员) (C++14 起)指针和一个空指针常量,或二个空指针常量(但要至少一个为 std::nullptr_t : 0 和 0 的比较遵循算术比较规则) (C++14 前)。
首先,应用指针转换(若参数为指向成员指针则为指向成员指针转换)、函数指针转换 (C++17 起)和限定转换到两个运算数,获得合成指针类型,如下
T
的指向 cv2 T
的指针,其中 T
为对象类型或 void ,则合成类型为“指向 void 的指针”,其中 cv12 为 cv1 与 cv2 的联合
4) 若二个运算数为指向带有不同 cv 限定的同一类型的指针,则合成类型为指向带参数的 cv 限定联合的同一类型的指针。
|
(C++14 前) |
4) 若运算数类型为 P1 ,指向(可能 cv 限定) T1 的指针,和 P2 ,指向(可能 cv 限定) T2 的指针,而若 T1 与 T2 相同或是 T2 的基类,则合成指针类型为 P1 与 P2 的 cv 结合类型。否则,若 T2 为 T1 的基类,则合成指针类型为 P2 与 P1 的 cv 结合类型。
5) 若运算数的类型为 MP1 ,指向(可能 cv 限定) U1 成员的指针,和 MP2 ,指向(可能 cv 限定) U2 成员的指针,而若 U1 与 U2 相同或从它导出,则合成指针类型为 MP1 和 MP2 的“ cv 结合”类型。否则,若 U2 导出自 U1 ,则合成指针类型为 MP2 与 MP1 的 cv 结合类型。
6) 若运算数 P1 和 P2 的类型为混合的多层指针和指向成员指针,而层数相同,仅在任何层上的 cv 限定有别,则合成指针类型为 P1 与 P2 的 cv 结合类型
上面的定义中,二个指针类型 P1 和 P2 的 cv 结合类型,是拥有相同的层数,在每层拥有同 P1 的类型,除了每层上的 cv 限定设定如下的类型 P3 : a) 在异于顶层的每级上, cv 限定为该层上 P1 与 P2 的 cv 限定联合
b) 若结果在任何层上的 cv 限定异于同一层上 P1 的或 P2 的 cv 限定,则添加 const 到在顶层和此层间的每一层。
例如, void* 与 const int* 的合成指针类型为 const void* 。 int** 与 const int** 的合成指针类型为 const int* const* 。注意 C++14 前无法比较 int** 和 const int** 。 |
(C++14 起) |
在上述之外,指向函数指针和指向 noexcept 函数指针(只要函数类型相同)的合成指针类型为指向函数指针。 |
(C++17 起) |
注意这隐含任何指针都能与 void* 比较。
二个指向对象指针(转换后)的比较结果定义如下:
&obj+1
比较大于 &obj
。 (C++17 起)比较二个(转换后)指针相等性的结果定义如下:
比较二个指向成员指针(转换后)的结果定义如下:
若指针 p
比较等于指针 q
,则 p<=q
和 p>=q
都产出 true
而 p<q
和 p>q
都产出 false
。
若指针 p
比较大于指针 q
,则 p>=q
、 p>q
、 q<=p
和 q<p
都产出 true
而 p<=q
、 p<q
、 q>=p
和 q>p
都产出 false
。
若不指定二个指针比较大于或比较相等,则比较结果未指定。结果可以为非确定的,而且甚至不必在程序的同一次执行中,拥有相同运算数的相同表达式的多次求值之间一致:
int x, y; bool f(int* p, int* q) { return p < q; } assert(f(&x, &y) == f(&x, &y)); // 在服从标准的实现中可能出事
针对用户定义运算符的重载决议中,对于每个提升后算术类型 L 和 R ,包括枚举类型,下列函数签名参与重载决议:
bool operator<(L, R); |
||
bool operator>(L, R); |
||
bool operator<=(L, R); |
||
bool operator>=(L, R); |
||
bool operator==(L, R); |
||
bool operator!=(L, R); |
||
对于每个为指向对象指针或指向函数指针或 std::nullptr_t (C++14 前)的类型 P
,下列函数签名参与重载决议:
bool operator<(P, P); |
||
bool operator>(P, P); |
||
bool operator<=(P, P); |
||
bool operator>=(P, P); |
||
bool operator==(P, P); |
||
bool operator!=(P, P); |
||
对于每个为指向成员对象或成员函数指针或 std::nullptr_t 的类型 MP
,下列函数签名参与重载决议:
bool operator==(MP, MP); |
||
bool operator!=(MP, MP); |
||
[编辑] 示例
#include <iostream> struct Foo { int n1; int n2; }; union Union { int n; double d; }; int main() { std::cout << std::boolalpha; char a[4] = "abc"; char* p1 = &a[1]; char* p2 = &a[2]; std::cout << "Pointers to array elements: p1 == p2 " << (p1 == p2) << ", p1 < p2 " << (p1 < p2) << '\n'; Foo f; int* p3 = &f.n1; int* p4 = &f.n2; std::cout << "Pointers to members of a class: p3 == p4 " << (p3 == p4) << ", p3 < p4 " << (p3 < p4) << '\n'; Union u; int* p5 = &u.n; double* p6 = &u.d; std::cout << "Pointers to members of a union: p5 == (void*)p6 " << (p5 == (void*)p6) << ", p5 < p6 " << (p5 < (void*)p6) << '\n'; }
输出:
Pointers to array elements: p1 == p2 false, p1 < p2 true Pointers to members of a class: p3 == p4 false, p3 < p4 true Pointers to members of a union: p5 == (void*)p6 true, p5 < p6 false
[编辑] 注意
因为这些运算符从左到右组合,故表达式 a<b<c 被分析为 (a<b)<c ,而非 a<(b<c) 或 (a<b)&&(b<c) 。
用户定义的 operator< 的常见要求是严格弱序。尤其是,这为用比较 (Compare
) 类型工作的标准算法和容器 std::sort 、 std::max_element 、 std::map 等所要求。
尽管比较随机来源(例如不都指向同一数组元素)的指针结果未指定,许多实现提供指针的严格全序,例如若它们被实现为连续虚地址空间中的地址。不如此的实现(例如并非指针的所有位都是内存地址的一部分,而在比较中必须被忽略,或要求额外计算,或其他情况下指针与整数并非 1 对 1 关系),要提供 std::less 对指针的拥有该保证的特化。这使得程序能以随机来源的所有指针为标准关联容器,如 std::set 或 std::map 中的关键。
对于既可比较相等 (EqualityComparable
) 又可比较小于 (LessThanComparable
) 的类型, C++ 标准库在相等,即表达式 a == b 的值,和等价,即表达式 !(a < b) && !(b < a) 的值,之间做出区别。
指针与空指针常量间的比较在 C++14 中移除。
void f(char * p) { if (p > 0) { ... } // C++98..C++11 中 OK , C++14 中不能编译 if (p > nullptr) { ... } // C++11 中 OK , C++14 中不能编译 }
三路比较三路比较运算符拥有形式
表达式返回对象,使得
若运算数之一有 bool 类型而另一个没有,则程序为病式。 若二个运算数均拥有算数类型,则应用通常算术转换到运算数,然后
若二个运算数都拥有相同枚举类型 E ,则运算符产出转换运算数为 E 的底层类型再应用 <=> 到转换后的运算数的结果。 若至少一个运算数为指针或指向成员指针,则按需应用数组到指针转换、导出到基类指针转换、函数指针转换和限定转换,以转换它们为同一指针类型。 若结果指针类型为函数指针、指向成员指针或 std::nullptr_t ,则 p <=> q 返回 std::strong_equality 类型纯右值:
若结果指针类型为对象指针类型,则 p <=> q 返回 std::strong_ordering 类型纯右值:
针对用户定义运算符的重载决议中,对于指针或枚举类型
其中 R 是上面定义的顺序类别类型。 对于每个为指向成员指针类型或 std::nullptr_t 类型的 T ,下列函数签名参与重载决议:
注意能为类类型自动生成三路比较,见默认比较。 若二个运算数均为数组,则三路比较为病式,除非在比较数组类型成员。 unsigned int i = 1; auto r = -1 < i; // 既存陷阱:返回 false auto r = -1 <=> i // 错误:非均相
|
(C++20 起) |
[编辑] 标准库
比较运算符为标准库中的许多类重载。
检查对象是否指代相同类型 ( std::type_info 的公开成员函数)
| |
比较两个 error_code (函数) | |
比较 error_condition 和 error_code (函数) | |
按字典序比较 pair 中的值 (函数模板) | |
按字典顺序比较 tuple 中的值 (函数模板) | |
比较其内容 ( std::bitset 的公开成员函数)
| |
比较两个分配器实例 ( std::allocator 的公开成员函数)
| |
与另一个 unique_ptr 或 nullptr 进行比较 (函数模板) | |
与另一个 shared_ptr 或 nullptr 进行比较 (函数模板) | |
比较 std::function 和 nullptr (函数模板) | |
比较两个时长 (函数模板) | |
比较两个时间点 (函数模板) | |
比较两个 scoped_allocator_adaptor 实例 ( std::scoped_allocator_adaptor 的公开成员函数)
| |
比较底层 std::type_info 对象 ( std::type_index 的公开成员函数)
| |
以字典序比较二个字符串 (函数模板) | |
locale 对象之间的相等性比较 ( std::locale 的公开成员函数)
| |
按照字典顺序比较 array 中的值 (函数模板) | |
按照字典顺序比较 deque 中的值 (函数模板) | |
按照字典顺序比较 forward_list 中的值 (函数模板) | |
按照字典顺序比较 list 中的值 (函数模板) | |
按照字典顺序比较 vector 中的值 (函数模板) | |
按照字典顺序比较 map 中的值 (函数模板) | |
按照字典顺序比较 multimap 中的值 (函数模板) | |
按照字典顺序比较 set 中的值 (函数模板) | |
按照字典顺序比较 multiset 中的值 (函数模板) | |
比较 unordered_map 中的值 (函数模板) | |
比较 unordered_multimap 中的值 (函数模板) | |
比较 unordered_set 中的值 (函数模板) | |
比较 unordered_multiset 中的值 (函数模板) | |
按照字典顺序比较 queue 中的值 (函数模板) | |
按照字典顺序比较 stack 中的值 (函数模板) | |
比较底层迭代器 (函数模板) | |
比较底层迭代器 (函数模板) | |
比较两个 istream_iterator (函数模板) | |
比较两个 istreambuf_iterator (函数模板) | |
比较两个复数或一个复数和一个标量 (函数模板) | |
比较两个 valarrays,或比较一个 valarray 和一个值 (函数模板) | |
比较两个伪随机数引擎的内部状态 (函数) | |
比较二个分布对象 (函数) | |
比较两个 sub_match 对象 (函数模板) | |
以字典序比较两个匹配结果的值 (函数模板) | |
比较两个 regex_iterator ( std::regex_iterator 的公开成员函数)
| |
比较两个 regex_token_iterator ( std::regex_token_iterator 的公开成员函数)
| |
比较二个 thread::id 对象 (函数) |
命名空间 rel_ops 提供泛型运算符 != 、 > 、 <= 及 >=
定义于头文件
<utility> | |
定义于命名空间
std::rel_ops | |
(C++20 中弃用) |
自动生成基于用户定义的 operator== 和 operator< 的比较运算符 (函数模板) |
[编辑] 参阅
常见运算符 | ||||||
---|---|---|---|---|---|---|
赋值 | 自增 自减 |
算术 | 逻辑 | 比较 | 成员访问 | 其他 |
a = b |
++a |
+a |
!a |
a == b |
a[b] |
a(...) |
特殊运算符 | ||||||
static_cast 转换一个类型为另一相关类型 |