C++ 参考手册
- C++11
- C++14
- C++17
- C++20
- C++ 编译器支持情况表
- 独立与宿主实现
- C++ 语言
- 变量模板(C++14 起)
- 整数字面量
- 聚合初始化
- 比较运算符
- 默认比较(C++20 起)
- 转义序列
- for 循环
- while 循环
- 用户定义转换
- SFINAE
- 主函数
- ASCII 码表
- 标识符
- 类型
- 内存模型
- 对象
- 基本概念
- 表达式
- 声明
- 初始化
- 函数
- 语句
- 类
- 运算符重载
- 模板
- 异常
- 事务性内存
- 占位符类型说明符 (C++11 起)
- decltype 说明符
- 函数声明
- final 说明符 (C++11 起)
- override 说明符(C++11 起)
- 引用声明
- 移动构造函数
- 移动赋值运算符
- 枚举声明
- constexpr 说明符(C++11 起)
- 列表初始化 (C++11 起)
- 构造函数与成员初始化器列表
- using 声明
- nullptr,指针字面量
- 基础类型
- 类型别名,别名模版 (C++11 起)
- 形参包
- 联合体声明
- 字符串字面量
- 用户定义字面量 (C++11 起)
- 属性说明符序列(C++11 起)
- Lambda 表达式 (C++11 起)
- noexcept 说明符 (C++11 起)
- noexcept 运算符 (C++11 起)
- alignof 运算符(C++11 起)
- alignas 说明符 (C++11 起)
- 存储类说明符
- 基于范围的 for 循环 (C++11 起)
- static_assert 声明
- 隐式转换
- 代用运算符表示
- 自增/自减运算符
- 折叠表达式(C++17 起)
- 类模板实参推导(C++17 起)
- 模板形参与模板实参
- if 语句
- inline 说明符
- 结构化绑定声明 (C++17 起)
- switch 语句
- 字符字面量
- 命名空间
- 求值顺序
- 复制消除
- consteval 说明符 (C++20 起)
- constinit 说明符 (C++20 起)
- 协程 (C++20)
- 模块 (C++20 起)
- 约束与概念 (C++20 起)
- new 表达式
- do-while 循环
- continue 语句
- break 语句
- goto 语句
- return 语句
- 动态异常说明
- throw 表达式
- try 块
- 命名空间别名
- 类声明
- cv(const 与 volatile)类型限定符
- 默认初始化
- 值初始化(C++03 起)
- 零初始化
- 复制初始化
- 直接初始化
- 常量初始化
- 引用初始化
- 值类别
- C++ 运算符优先级
- 布尔字面量
- 浮点字面量
- typedef 说明符
- 显式类型转换
- static_cast 转换
- dynamic_cast 转换
- const_cast 转换
- reinterpret_cast 转换
- delete 表达式
- 构造函数与成员初始化器列表
- this 指针
- 访问说明符
- 友元声明
- virtual 函数说明符
- explicit 说明符
- 静态成员
- 默认构造函数
- 复制构造函数
- 复制赋值运算符
- 析构函数
- 类模板
- 函数模板
- 显式(全)模板特化
- 汇编声明
- C++ 的历史
- 作用域
- 生存期
- 定义与单一定义规则(ODR)
- 名字查找
- 有限定的名字查找
- 无限定的名字查找
- 如同规则
- 未定义行为
- 翻译阶段
- 常量表达式
- 赋值运算符
- 算术运算符
- 逻辑运算符
- 成员访问运算符
- 其他运算符
- sizeof 运算符
- typeid 运算符
- 指针声明
- 数组声明
- 语言链接
- 详述类型说明符
- 默认实参
- 变长实参
- 实参依赖查找
- 重载决议
- 重载函数的地址
- 注入类名
- 非静态数据成员
- 非静态成员函数
- 嵌套类
- 派生类
- 空基类优化
- 抽象类
- 位域
- 转换构造函数
- 成员模板
- 模板实参推导
- 部分模板特化
- sizeof... 运算符
- 待决名
- 函数 try 块
- 扩充命名空间 std
- 字母缩写
- RAII
- 三/五/零之法则
- PImpl
- 零开销原则
- 类型
- 隐式转换
- 注释
- C++ 关键词
- 预处理器
- C++ 标准库头文件
- 具名要求
- 功能特性测试 (C++20)
- 工具库
- 类型支持(基本类型、RTTI、类型特性)
- 概念库 (C++20)
- 错误处理
- 动态内存管理
- 日期和时间工具
- 字符串库
- 容器库
- 迭代器库
- 范围库 (C++20)
- 算法库
- 数值库
- 输入/输出库
- 文件系统库
- 本地化库
- 正则表达式库
- 原子操作库
- 线程支持库
- 实验性 C++ 特性
- 有用的资源
- 索引
- std 符号索引
- 协程支持 (C++20)
- C++ 关键词
比较运算符
比较参数。
运算符名 | 语法 | 可重载 | 原型示例(对 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
|
是 | /*见说明*/ T::operator <=>(const T2 &b) const; | /*见说明*/ 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 在应用左值到右值、数组到指针和函数到指针标准转换后,必须具有下列类型之一
- 算术或枚举类型(见下文的算术比较运算符)
- 指针类型(见下文的指针比较运算符)
若两个运算数在应用这些转换前均具有数组类型,则这种比较被弃用。 (C++20 起)
任何情况下,结果均为 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:NULL 和 NULL 的比较遵循算术比较规则) (C++14 前)。
首先,对两个操作数应用指针转换(若参数为成员指针则为成员指针转换)、函数指针转换 (C++17 起)和限定性转换,以获得合成指针类型,规则如下
T
)指向 cv2 T
的指针,其中 T
为对象类型或 void,则合成类型为“指向 cv12 void 的指针”,其中 cv12 为 cv1 与 cv2 的合并
4) 若两个操作数均为指向带有不同 cv 限定的同一类型的指针,则合成类型为指向同一类型的指针并带有两个实参 cv 限定性的合并 cv 限定性。
|
(C++14 前) |
4) 若操作数的类型分别为指向(可能 cv 限定)T1 的指针 P1,和指向(可能 cv 限定)T2 的指针 P2,且若 T1 与 T2 相同或是 T2 的基类,则合成指针类型为 P1 与 P2 的 cv 结合类型。否则,若 T2 为 T1 的基类,则合成指针类型为 P2 与 P1 的 cv 结合类型。
5) 若操作数的类型分别为指向(可能 cv 限定)U1 类型的 T1 的成员指针,和指向(可能 cv 限定)U2 类型的 T2 的成员指针,且若 T1 与 T2 相同或派生于 T2,则合成指针类型为 MP1 和 MP2 的 cv 结合类型。否则,若 T2 派生于 T1,则合成指针类型为 MP2 与 MP1 的 cv 结合类型。
6) 若操作数 P1 和 P2 的类型具有相同层数的多层混合指针和成员指针类型,而仅在任何层上的 cv 限定性有别,则合成指针类型为 P1 与 P2 的 cv 结合类型
上面的定义中,两个指针类型 P1 和 P2 的 cv 结合类型,是拥有相同的层数且每层具有与 P1 相同类型的类型 P3,其中每层上的 cv 限定性设定如下: 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 的底层类型再对转换后的操作数应用 <=> 的结果。 若至少一个操作数为指针或成员指针,则按需应用数组到指针转换、派生类到基类指针转换、函数指针转换和限定性转换,以将它们转换为同一指针类型,且结果指针类型为对象指针类型,则 p <=> q 返回 std::strong_ordering 类型的纯右值:
否则程序非良构。 在针对用户定义运算符的重载决议中,对于指针或枚举类型
其中 R 是上文所定义的排序类别类型。 注解类类型可以自动生成三路比较,见默认比较。 如果两个运算数均为数组,则除了比较数组类型的类成员之外,三路比较均为非良构。 unsigned int i = 1; auto r = -1 < i; // 既存陷阱:返回 false auto r2 = -1 <=> i; // 错误:要求窄化转换
|
(C++20 起) |
标准库
比较运算符为标准库中的许多类所重载。
(C++20 中移除) |
检查对象是否指代相同类型 ( std::type_info 的公开成员函数) |
(C++20 中移除)(C++20 中移除)(C++20) |
比较两个 error_code (函数) |
(C++20 中移除)(C++20 中移除)(C++20) |
比较 error_condition 和 error_code (函数) |
(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20) |
按字典序比较 pair 中的值 (函数模板) |
(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20) |
按字典顺序比较 tuple 中的值 (函数模板) |
(C++20 中移除) |
比较其内容 ( std::bitset<N> 的公开成员函数) |
(C++20 中移除) |
比较两个分配器实例 ( std::allocator<T> 的公开成员函数) |
(C++20 中移除)(C++20) |
与另一个 unique_ptr 或 nullptr 进行比较 (函数模板) |
(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20) |
与另一个 shared_ptr 或 nullptr 进行比较 (函数模板) |
(C++20 中移除) |
比较 std::function 和 nullptr (函数模板) |
(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20) |
比较两个时长 (函数模板) |
(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20) |
比较两个时间点 (函数模板) |
(C++20 中移除) |
比较两个 scoped_allocator_adaptor 实例 ( std::scoped_allocator_adaptor<OuterAlloc,InnerAlloc...> 的公开成员函数) |
(C++20 中移除)(C++20) |
比较底层 std::type_info 对象 ( std::type_index 的公开成员函数) |
(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20) |
以字典序比较两个字符串 (函数模板) |
(C++20 中移除) |
locale 对象之间的相等性比较 ( std::locale 的公开成员函数) |
(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20) |
按照字典顺序比较 array 中的值 (函数模板) |
(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20) |
按照字典顺序比较 deque 中的值 (函数模板) |
(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20) |
按照字典顺序比较 forward_list 中的值 (函数模板) |
(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20) |
按照字典顺序比较 list 中的值 (函数模板) |
(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20) |
按照字典顺序比较 vector 中的值 (函数模板) |
(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20) |
按照字典顺序比较 map 中的值 (函数模板) |
(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20) |
按照字典顺序比较 multimap 中的值 (函数模板) |
(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20) |
按照字典顺序比较 set 中的值 (函数模板) |
(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20) |
按照字典顺序比较 multiset 中的值 (函数模板) |
(C++20 中移除) |
比较 unordered_map 中的值 (函数模板) |
(C++20 中移除) |
比较 unordered_multimap 中的值 (函数模板) |
(C++20 中移除) |
比较 unordered_set 中的值 (函数模板) |
(C++20 中移除) |
比较 unordered_multiset 中的值 (函数模板) |
(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20) |
按照字典顺序比较 queue 中的值 (函数模板) |
(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20) |
按照字典顺序比较 stack 中的值 (函数模板) |
比较底层迭代器 (函数模板) | |
(C++20 中移除)(C++20) |
比较底层迭代器 (函数模板) |
(C++20 中移除) |
比较两个 istream_iterator (函数模板) |
(C++20 中移除) |
比较两个 istreambuf_iterator (函数模板) |
(C++20 中移除) |
比较两个复数,或一个复数与一个标量 (函数模板) |
比较两个 valarrays,或比较一个 valarray 和一个值 (函数模板) | |
比较两个伪随机数引擎的内部状态 (函数) | |
比较两个分布对象 (函数) | |
(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20) |
比较一个 sub_match 与另一 sub_match 、字符串或字符 (函数模板) |
(C++20 中移除) |
以字典序比较两个匹配结果的值 (函数模板) |
(C++20 中移除) |
比较两个 regex_iterator ( std::regex_iterator<BidirIt,CharT,Traits> 的公开成员函数) |
(C++20 中移除) |
比较两个 regex_token_iterator ( std::regex_token_iterator<BidirIt,CharT,Traits> 的公开成员函数) |
(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20) |
比较两个 thread::id 对象 (函数) |
命名空间 rel_ops 提供了泛型运算符 !=、>、<= 及 >=
定义于头文件
<utility> | |
定义于命名空间
std::rel_ops | |
(C++20 中弃用) |
自动生成基于用户定义的 operator== 和 operator< 的比较运算符 (函数模板) |
参阅
常见运算符 | ||||||
---|---|---|---|---|---|---|
赋值 | 自增 自减 |
算术 | 逻辑 | 比较 | 成员访问 | 其他 |
a = b |
++a |
+a |
!a |
a == b |
a[b] |
a(...) |
特殊运算符 | ||||||
static_cast 转换一个类型为另一相关类型 |