比较运算符

来自cppreference.com
< cpp‎ | language
 
 
 
表达式
概述
值类别(左值 lvalue、右值 rvalue、亡值 xvalue)
求值顺序(序列点)
常量表达式
不求值表达式
初等表达式
lambda 表达式(C++11)
字面量
整数字面量
浮点字面量
布尔字面量
字符字面量,包含转义序列
字符串字面量
空指针字面量(C++11)
用户定义字面量(C++11)
运算符
赋值运算符a=ba+=ba-=ba*=ba/=ba%=ba&=ba|=ba^=ba<<=ba>>=b
自增与自减++a--aa++a--
算术运算符+a-aa+ba-ba*ba/ba%b~aa&ba|ba^ba<<ba>>b
逻辑运算符a||ba&&b!a
比较运算符a==ba!=ba<ba>ba<=ba>=b
成员访问运算符a[b]*a&aa->ba.ba->*ba.*b
其他运算符a(...)a,ba?b:c
运算符的替代表示形式
优先级和结合性
折叠表达式(C++17)
new 表达式
delete 表达式
throw 表达式
alignof
sizeof
sizeof...(C++11)
typeid
noexcept(C++11)
运算符重载
类型转换
隐式转换
const_cast
static_cast
reinterpret_cast
dynamic_cast
显式转换 (T)aT(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);
注意
  • 所有的内建运算符均返回 bool,而大多数用户定义的重载也返回 bool,以便用户定义的运算符可以和内建运算符以相同方式使用。不过,在用户定义的运算符重载中,任何类型都可以作为其返回类型(包括 void)。
  • T2 可以是包括 T 在内的任何类型。

目录

[编辑] 解释

返回对两个实参的值进行比较的布尔结果,其实参均不被改动。

[编辑] 算术比较运算符

对于每对提升后的算术类型 LR,包括枚举类型,有如下函数签名参与重载解析:

bool operator<(L, R);
bool operator>(L, R);
bool operator<=(L, R);
bool operator>=(L, R);
bool operator==(L, R);
bool operator!=(L, R);

如果操作数具有算术或(有作用域或无作用域)枚举类型,则根据针对算术运算符的规则实施一般算术转换。对转换后的值进行比较:

[编辑] 示例

#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

[编辑] 指针的比较运算符

对于每个对象指针或函数指针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);

比较运算符可以用于比较两个指针(或成员指针,仅 operator==operator!= 可以),或者比较一个成员 (C++14 起)指针和一个空指针常量,或者两个空指针常量(但仅当其中至少一个是 std::nullptr_t 才可以:对 NULL 和 NULL 的比较遵循的是算术比较规则) (C++14 前)

首先,对两个操作数都进行指针转换(当实参为成员指针时为成员指针转换),函数指针转换, (C++17 起)限定性转换,以获得其合成指针类型,过程如下:

1) 当两个操作数均为空指针常量时,合成指针类型为 std::nullptr_t
2) 当一个操作数为空指针常量而另一个为指针时,合成指针类型就是该指针类型
3) 当一个操作数为 cv1 void 的指针而另一个为(对于某个类型 Tcv2 T 的指针时,合成指针类型为“cv12 void 的指针”,其中 cv12cv1cv2 的合并
4) 当两个操作数均为相同类型的指针但带有不同的 cv 限定性时,合成指针类型相同类型的指针,其 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 类型的 T1 的成员指针)和 MP2(即(可能被 cv 限定的)U2 类型的 T2 的成员指针),并且 T1 和 T2 相同或者派生于 T2 时,合成指针类型为 MP1 和 MP2 的 cv 合并类型。否则,当 T2 派生于 T1 时,合成指针类型为 MP2 和 MP1 的 cv 合并类型。
6) 当两个操作数的类型 P1 和 P2 是具有相同级数的指针和成员指针的多级混合类型,且仅在任何级别的 cv 限定性上有所差异时,合成指针类型为 P1 和 P2 的 cv 合并类型。

以上定义中,两个指针类型 P1 和 P2 的 cv 合并 类型,是一个类型 P3,具有与 P1 相同数量的级数和各级的类型,但其各级的 cv 限定性设定如下:

a) 除顶级外的每一级,为 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

如果并未指明两指针比较大于或者比较相等,则其比较的结果是未指明的。

[编辑] 示例

#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,等等。

虽然对任意来源的指针(即并非都指向同一个数组的成员)的进行比较的结果是未指明的,许多实现都为指针提供了严格全序,比如实现为连续虚拟地址空间中的地址。不这样做的实现(比如指针中并非所有的位都构成内存地址而必须在比较中予以忽略,或者需要进行额外的计算否则指针和整数就并非一对一的关系),为指针提供 std::less 的一个特化以提供这种保证。这使得将任意来源的指针用作如 std::setstd::map 这样的标准关联容器的键成为可能。

对于同时为 EqualityComparableLessThanComparable 的类型,C++ 标准库在相等性(表达式 a == b 的值)和等价性(表达式 !(a < b) && !(b < a) 的值)之间进行了区分。

C++14 移除了对指针和空指针常量的比较

void f(char * p)
{
  if (p > 0) { ... } // 从 C++98 到 C++11 没问题,但在 C++14 中无法编译
  if (p > nullptr) { ... } // 从 C++98 到 C++11 没问题,但在 C++14 中无法编译
}

[编辑] 标准库

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

检查对象是否指代相同类型
(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 对象
(函数) [编辑]
基于用户定义的 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
&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 回收内存
sizeof 查询类型的大小
sizeof... 查询形参包的大小(C++11 起)
typeid 查询类型的类型信息
noexcept 检查表达式是否会抛出异常(C++11 起)
alignof 查询类型的对齐要求(C++11 起)