比较运算符

来自cppreference.com
< cpp‎ | language
 
 
 
表达式
概述
值类别(左值 lvalue 、右值 rvalue 、亡值 xvalue )
求值顺序(序列点)
常量表达式
不求值表达式
初等表达式
lambda 表达式(C++11)
字面量
整数字面量
浮点字面量
布尔字面量
字符字面量,包含转义序列
字符串字面量
空指针字面量(C++11)
用户定义字面量(C++11)
运算符
赋值运算符a=b, a+=b, a-=b, a*=b, a/=b, a%=b, a&=b, a|=b, a^=b, a<<=b, a>>=b
自增与自减++a, --a, a++, a--
算术运算符+a, -a, a+b, a-b, a*b, a/b, a%b, ~a, a&b, a|b, a^b, a<<b, a>>b
逻辑运算符a||b, a&&b, !a
比较运算符a==b, a!=b, a<b, a>b, a<=b, a>=b, a<=>b(C++20)
成员访问运算符a[b], *a, &a, a->b, a.b, a->*b, a.*b
其他运算符a(...), a,b, a?b:c
默认比较(C++20)
运算符的替代表示
优先级和结合性
折叠表达式(C++17)
new 表达式
delete 表达式
throw 表达式
alignof
sizeof
sizeof...(C++11)
typeid
noexcept(C++11)
运算符重载
类型转换
隐式转换
const_cast
static_cast
reinterpret_cast
dynamic_cast
显式转换 (T)a, T(a)
用户定义转换
 

比较参数。

运算符名 语法 可重载 原型示例(对 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);
注意
  • 在内建运算符返回 bool 处,大多数用户定义重载亦返回 bool ,使得用户定义运算符能以同内建运算符的方式使用。然而,在用户定义运算符重载中,任何类型都能用作返回类型(包含 void )。
  • T2 能为任何类型,包括 T

目录

[编辑] 双路比较

双路比较运算符拥有形式

lhs < rhs (1)
lhs > rhs (2)
lhs <= rhs (3)
lhs >= rhs (4)
lhs == rhs (5)
lhs != rhs (6)
1)lhs 小于 rhs 则返回 true ,否则返回 false
2)lhs 大于 rhs 则返回 true ,否则返回 false
3)lhs 小于或等于 rhs 则返回 true ,否则返回 false
4)lhs 大于或等于 rhs 则返回 true ,否则返回 false
5)lhs 等于 rhs 则返回 true ,否则返回 false
6)lhs 不等于 rhs 则返回 true ,否则返回 false

所有情况下,对于内建运算符, lhsrhs 在应用左值到右值数组到指针函数到指针标准转换后,必须拥有下列类型之一

  • 算术或枚举类型(见后述算术比较运算符)
  • 指针类型(见下方指针比较运算符)

若两个运算数在应用这些转换前均拥有数组类型,则这种比较被弃用。 (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 : 0 和 0 的比较遵循算术比较规则) (C++14 前)

首先,应用指针转换(若参数为指向成员指针则为指向成员指针转换)、函数指针转换 (C++17 起)限定转换到两个运算数,获得合成指针类型,如下

1) 若二个运算数均为空指针常量,则合成指针类型为 std::nullptr_t
2) 若一个运算数为空指针常量,而另一个为指针,则合成类型准确地为指针类型
3) 若一个运算数为指向 cv1 void 的指针,而另一个为某类型 T 的指向 cv2 T 的指针,其中 T 为对象类型或 void ,则合成类型为“指向 void 的指针”,其中 cv12cv1cv2 的联合
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* 比较。

二个指向对象指针(转换后)的比较结果定义如下:

1) 若二个指针指向同一数组的不同元素,或同一数组的不同元素内的子对象,则指向拥有较高下标的元素的指针比较大于另一指针。换言之,比较指针的结果与比较其所指向的元素下标结果相同。
2) 若一个指针指向数组元素,或数组元素的子对象,而另一指针指向数组末元素后一位置,则后者比较大于前者。指向单个对象的指针被当做指向单元素数组的指针: &obj+1 比较大于 &obj (C++17 起)
3) 若在非联合类类型的对象内,二个指针指向拥有相同成员访问的不同非静态数据成员,或指向这种成员的数组元素,递归处理,则指向较后声明的成员的指针比较大于另一指针。换言之,三个成员访问模式的每一者中的类成员按声明顺序置于内存中。

比较二个(转换后)指针相等性的结果定义如下:

1) 若两个指针均为空指针值,则它们比较相等
2) 若指针指向函数,且指向同一函数,则比较相等
3) 若指针指向对象,且表示相同地址,则它们比较相等(这包含二个指向同一联合体的不同非静态成员的指针、指向标准布局结构体与其首成员的指针、由 reinterpret_cast 关联的指针等)
4) 所有其他指针比较不相等。

比较二个指向成员指针(转换后)的结果定义如下:

1) 若两个指向成员指针均为空成员指针值,则它们比较相等
2) 否则,若二个指向成员指针之一为空成员指针值,则它们比较不相等。
3) 否则,若其中之一为指向虚成员函数的指针,则结果未指定。
4) 否则,二个指向成员指针相等,若且唯若假如用关联类类型的假想对象解引用,则它们会指代相同最终导出类或相同子对象的同一成员。
5) 否则它们比较不相等。

若指针 p 比较等于指针 q ,则 p<=qp>=q 都产出 truep<qp>q 都产出 false

若指针 p 比较大于指针 q ,则 p>=qp>qq<=pq<p 都产出 truep<=qp<qq>=pq>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::sortstd::max_elementstd::map 等所要求。

尽管比较随机来源(例如不都指向同一数组元素)的指针结果未指定,许多实现提供指针的严格全序,例如若它们被实现为连续虚地址空间中的地址。不如此的实现(例如并非指针的所有位都是内存地址的一部分,而在比较中必须被忽略,或要求额外计算,或其他情况下指针与整数并非 1 对 1 关系),要提供 std::less 对指针的拥有该保证的特化。这使得程序能以随机来源的所有指针为标准关联容器,如 std::setstd::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 中不能编译
}

三路比较

三路比较运算符拥有形式

lhs <=> rhs (1)

表达式返回对象,使得

  • lhs < rhs(a <=> b) < 0
  • lhs > rhs(a <=> b) > 0
  • 而若 lhsrhs 相等/等价则 (a <=> b) == 0

若运算数之一有 bool 类型而另一个没有,则程序为病式。

若二个运算数均拥有算术类型,或若一个拥有无作用域枚举类型而另一个有整数类型,则应用通常算术转换到运算数,然后

  • 若要求异于从整数类型到浮点类型的窄化转换,则程序为病式。
  • 否则,若运算数拥有整数类型,则运算符产出 std::strong_ordering 类型纯右值:
  • 若两个运算数算术上相等则为 std::strong_ordering::equal
  • 若第一运算数算术上小于第二个则为 std::strong_ordering::less
  • 否则为 std::strong_ordering::greater
  • 否则,运算数拥有浮点类型,而运算符产出 std::partial_ordering 类型纯右值。表达式 a <=> b 产出
  • a 小于 b 则为 std::partial_ordering::less
  • a 大于 b 则为 std::partial_ordering::greater
  • a 等价于 b 则为 std::partial_ordering::equivalent-0 <=> +0 为等价)
  • 否则为 std::partial_ordering::unorderedNaN <=> anything 为无序)

若二个运算数都拥有相同枚举类型 E ,则运算符产出转换运算数为 E 的底层类型再应用 <=> 到转换后的运算数的结果。

若至少一个运算数为指针或指向成员指针,则按需应用数组到指针转换、导出到基类指针转换、函数指针转换和限定转换,以转换它们为同一指针类型。

若结果指针类型为函数指针、指向成员指针或 std::nullptr_t ,则 p <=> q 返回 std::strong_equality 类型纯右值:

  • p == q 则为 std::strong_equality::equal
  • p != q 则为 std::strong_equality::unequal
  • 若相等比较对这些指针值未指定,则为未指定结果

若结果指针类型为对象指针类型,则 p <=> q 返回 std::strong_ordering 类型纯右值:

  • p == q 则为 std::strong_ordering::equal
  • q > p 则为 std::strong_ordering::less
  • p > q 则为 std::strong_ordering::greater
  • 若比较对这些指针值未指定(例如它们不指向同一对象或数组中元素时),则为未指定结果。

针对用户定义运算符的重载决议中,对于指针或枚举类型 T ,下列函数签名参与重载决议:

R operator<=>(T, T);

其中 R 是上面定义的顺序类别类型。

对于每个为指向成员指针类型或 std::nullptr_t 类型的 T ,下列函数签名参与重载决议:

std::strong_equality operator<=>(T, T);

注意

能为类类型自动生成三路比较,见默认比较

若二个运算数均为数组,则三路比较为病式,除非在比较数组类型成员。

unsigned int i = 1;
auto r = -1 < i; // 既存陷阱:返回 false
auto r2 = -1 <=> i; // 错误:要求窄化转换


(C++20 起)

[编辑] 标准库

比较运算符为标准库中的许多类重载。

检查对象是否指代相同类型
(std::type_info 的公开成员函数) [编辑]
比较两个 error_code
(函数) [编辑]
比较 error_condition 和 error_code
(函数) [编辑]
按字典序比较 pair 中的值
(函数模板) [编辑]
按字典顺序比较 tuple 中的值
(函数模板) [编辑]
比较其内容
(std::bitset 的公开成员函数) [编辑]
比较两个分配器实例
(std::allocator 的公开成员函数) [编辑]
与另一个 unique_ptrnullptr 进行比较
(函数模板) [编辑]
与另一个 shared_ptrnullptr 进行比较
(函数模板) [编辑]
比较 std::functionnullptr
(函数模板) [编辑]
比较两个时长
(函数模板) [编辑]
比较两个时间点
(函数模板) [编辑]
比较两个 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
自动生成基于用户定义的 operator==operator< 的比较运算符
(函数模板) [编辑]

[编辑] 参阅

运算符优先级

运算符重载

常见运算符
赋值 自增
自减
算术 逻辑 比较 成员访问 其他

a = b
a += b
a -= b
a *= b
a /= b
a %= b
a &= b
a |= b
a ^= b
a <<= b
a >>= b

++a
--a
a++
a--

+a
-a
a + b
a - b
a * b
a / b
a % b
~a
a & b
a | b
a ^ b
a << b
a >> b

!a
a && b
a || b

a == b
a != b
a < b
a > b
a <= b
a >= b
a <=> b

a[b]
*a
&a
a->b
a.b
a->*b
a.*b

a(...)
a, b
? :

特殊运算符

static_cast 转换一个类型为另一相关类型
dynamic_cast 在继承层级中转换
const_cast 添加或移除 cv 限定符
reinterpret_cast 转换类型到无关类型
C 风格转型static_castconst_castreinterpret_cast 的混合转换一个类型到另一类型
new 创建有动态存储期的对象
delete 销毁先前由 new 表达式创建的对象,并释放其所拥有的内存区域
sizeof 查询类型的大小
sizeof... 查询形参包的大小(C++11 起)
typeid 查询类型的类型信息
noexcept 查询表达式是否能抛出异常(C++11 起)
alignof 查询类型的对齐要求(C++11 起)

比较运算符C 文档