上传cppreference
This commit is contained in:
@@ -0,0 +1,329 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh" dir="ltr" class="client-nojs" xmlns="http://www.w3.org/1999/xhtml" xml:lang="zh">
|
||||
<head><meta http-equiv="x-ua-compatible" content="ie=edge">
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<title>默认比较(C++20 起)</title>
|
||||
<link rel="stylesheet" href="ext.css" />
|
||||
<link rel="stylesheet" href="site_modules.css" />
|
||||
</head>
|
||||
<body class="mediawiki ltr sitedir-ltr ns-0 ns-subject page-cpp_language_default_comparisons skin-cppreference2 action-view cpp-navbar">
|
||||
<div id="cpp-content-base">
|
||||
<div id="content"><a id="top"></a>
|
||||
<h1 id="firstHeading" class="firstHeading">默认比较<span class="t-mark-rev t-since-cxx20">(C++20 起)</span></h1>
|
||||
<div id="bodyContent">
|
||||
<div id="contentSub"><span class="subpages">< <a href="cpp.html">cpp</a>‎ | <a href="cpp-language.html">language</a></span></div>
|
||||
<div id="mw-content-text" lang="zh" dir="ltr" class="mw-content-ltr" xml:lang="zh">
|
||||
<p>提供一种方式,以要求编译器为某个类生成相一致的比较运算符。</p>
|
||||
<h3><span class="mw-headline" id=".E8.AF.AD.E6.B3.95">语法</span></h3>
|
||||
<table class="t-sdsc-begin">
|
||||
<tr>
|
||||
<td colspan="10" class="t-sdsc-sep"></td>
|
||||
</tr>
|
||||
<tr class="t-sdsc">
|
||||
<td><span class="t-spar">返回类型</span> <span class="t-spar">类名</span><code><b>::operator</b></code><span class="t-spar">运算符</span><code><b>(</b></code> <code><b>const</b></code> <span class="t-spar">类名</span> <code><b>&</b></code> <code><b>) const</b></code> <code><b>&</b></code><span class="t-mark">(可选)</span> <code><b>= default;</b></code></td>
|
||||
<td>(1)</td>
|
||||
<td class="t-sdsc-nopad"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="10" class="t-sdsc-sep"></td>
|
||||
</tr>
|
||||
<tr class="t-sdsc">
|
||||
<td><code><b>friend</b></code> <span class="t-spar">返回类型</span> <code><b>operator</b></code><span class="t-spar">运算符</span><code><b>(</b></code> <code><b>const</b></code> <span class="t-spar">类名</span> <code><b>&</b></code><code><b>,</b></code> <code><b>const</b></code> <span class="t-spar">类名</span> <code><b>&</b></code> <code><b>) = default;</b></code></td>
|
||||
<td>(2)</td>
|
||||
<td class="t-sdsc-nopad"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="10" class="t-sdsc-sep"></td>
|
||||
</tr>
|
||||
<tr class="t-sdsc">
|
||||
<td><code><b>friend</b></code> <span class="t-spar">返回类型</span> <code><b>operator</b></code><span class="t-spar">运算符</span><code><b>(</b></code> <span class="t-spar">类名</span><code><b>,</b></code> <span class="t-spar">类名</span> <code><b>) = default;</b></code></td>
|
||||
<td>(3)</td>
|
||||
<td class="t-sdsc-nopad"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="10" class="t-sdsc-sep"></td>
|
||||
</tr>
|
||||
</table>
|
||||
<table class="t-par-begin">
|
||||
<tr class="t-par">
|
||||
<td><span class="t-spar">运算符</span></td>
|
||||
<td>-</td>
|
||||
<td>比较运算符(<code><=></code>,<code>==</code>,<code>!=</code>,<code><</code>,<code>></code>,<code><=</code>,或 <code>>=</code>)</td>
|
||||
</tr>
|
||||
<tr class="t-par">
|
||||
<td><span class="t-spar">返回类型</span></td>
|
||||
<td>-</td>
|
||||
<td>运算符函数的返回类型
|
||||
<ul>
|
||||
<li>如果<span class="t-spar">运算符</span>是 <code><b><=></b></code>,必须是 <a href="cpp-language-auto.html"><code>auto</code></a> 或<a href="cpp-language-default_comparisons.html#.E8.87.AA.E5.AE.9A.E4.B9.89.E7.9A.84.E6.AF.94.E8.BE.83.E5.92.8C.E6.AF.94.E8.BE.83.E7.B1.BB.E5.88.AB">三种比较类别</a>之一,</li>
|
||||
<li>其他情况下,必须是 <span class="t-c"><span class="mw-geshi cpp source-cpp"><span class="kw4">bool</span></span></span></li>
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<h3><span class="mw-headline" id=".E8.A7.A3.E9.87.8A">解释</span></h3>
|
||||
<div class="t-li1"><span class="t-li">1)</span> 将默认比较函数声明为成员函数。</div>
|
||||
<div class="t-li1"><span class="t-li">2)</span> 将默认比较函数声明为非成员函数。</div>
|
||||
<div class="t-li1"><span class="t-li">3)</span> 将默认比较函数声明为非成员函数。参数按值传递。</div>
|
||||
<p>每当有值通过 <code><</code>,<code>></code>,<code><=</code>,<code>>=</code>,或 <code><=></code> 被比较且重载决议选择该重载时,三路比较函数(不管是否为默认)会被调用。</p>
|
||||
<p>每当有值通过 <code>==</code> 或 <code>!=</code> 被比较且重载决议选择该重载时,相等比较函数(不管是否为默认)会被调用。</p>
|
||||
<p>与默认的特殊成员函数类似,默认的比较函数在<a href="cpp-language-definition.html#ODR-use">被 ODR 使用</a>或<a href="cpp-language-constant_expression.html#Functions_and_variables_needed_for_constant_evaluation">被常量求值所需</a>时被定义。</p>
|
||||
<h3><span class="mw-headline" id=".E9.BB.98.E8.AE.A4.E6.AF.94.E8.BE.83">默认比较</span></h3>
|
||||
<h4><span class="mw-headline" id=".E9.BB.98.E8.AE.A4.E4.B8.89.E8.B7.AF.E6.AF.94.E8.BE.83">默认三路比较</span></h4>
|
||||
<p>默认的 <code>operator<=></code> 通过依次以计算 <code><=></code> 比较基类(从左到右,深度优先),然后是非静态成员(按声明顺序)子对象,递归地展开数组成员(按下标递增),并在发现不相等的结果时提前停止的方式执行字典序比较,即:</p>
|
||||
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
||||
<div class="cpp source-cpp">
|
||||
<pre class="de1"><span class="kw1">for</span> <span class="coMULTI">/* T 的每个基类或子对象 o */</span>
|
||||
<span class="kw1">if</span> <span class="br0">(</span><span class="kw4">auto</span> cmp <span class="sy1">=</span> <span class="kw1">static_cast</span><span class="sy1"><</span>R<span class="sy1">></span><span class="br0">(</span>compare<span class="br0">(</span>lhs.<span class="me1">o</span>, rhs.<span class="me1">o</span><span class="br0">)</span><span class="br0">)</span><span class="sy4">;</span> cmp <span class="sy3">!</span><span class="sy1">=</span> <span class="nu0">0</span><span class="br0">)</span> <span class="kw1">return</span> cmp<span class="sy4">;</span>
|
||||
<span class="kw1">return</span> <span class="kw1">static_cast</span><span class="sy1"><</span>R<span class="sy1">></span><span class="br0">(</span>strong_ordering<span class="sy4">::</span><span class="me2">equal</span><span class="br0">)</span><span class="sy4">;</span></pre></div>
|
||||
</div>
|
||||
<p>虚基子对象是否会多次被比较未被指明。</p>
|
||||
<p>如果被声明的返回类型是 <span class="t-c"><span class="mw-geshi cpp source-cpp"><span class="kw4">auto</span></span></span>,实际的返回类型是要被比较的基类,成员子对象和成员数组元素的公共比较类别(见 <a href="cpp-utility-compare-common_comparison_category.html"><tt>std::common_comparison_category</tt></a>)。这样在编写返回类型非平凡地依赖于成员的场合时会更容易,例如:</p>
|
||||
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
||||
<div class="cpp source-cpp">
|
||||
<pre class="de1"><span class="kw1">template</span><span class="sy1"><</span><span class="kw1">class</span> T1, <span class="kw1">class</span> T2<span class="sy1">></span>
|
||||
<span class="kw1">struct</span> P <span class="br0">{</span>
|
||||
T1 x1<span class="sy4">;</span>
|
||||
T2 x2<span class="sy4">;</span>
|
||||
<span class="kw1">friend</span> <span class="kw4">auto</span> operator<span class="sy1"><=></span><span class="br0">(</span><span class="kw4">const</span> P<span class="sy3">&</span>, <span class="kw4">const</span> P<span class="sy3">&</span><span class="br0">)</span> <span class="sy1">=</span> <span class="kw1">default</span><span class="sy4">;</span>
|
||||
<span class="br0">}</span><span class="sy4">;</span></pre></div>
|
||||
</div>
|
||||
<p>将返回类型设为 <span class="t-c"><span class="mw-geshi cpp source-cpp">R</span></span> ,每一对子对象 <span class="t-c"><span class="mw-geshi cpp source-cpp">a</span></span>, <span class="t-c"><span class="mw-geshi cpp source-cpp">b</span></span> 按如下方法进行比较:</p>
|
||||
<ul>
|
||||
<li>如果 <span class="t-c"><span class="mw-geshi cpp source-cpp">a <span class="sy1"><=></span> b</span></span> 可用,比较结果为 <span class="t-c"><span class="mw-geshi cpp source-cpp"><span class="kw1">static_cast</span><span class="sy1"><</span>R<span class="sy1">></span><span class="br0">(</span>a <span class="sy1"><=></span> b<span class="br0">)</span></span></span>。</li>
|
||||
<li>否则,如果 <span class="t-c"><span class="mw-geshi cpp source-cpp">operator<span class="sy1"><=></span></span></span> 的重载决议为 <span class="t-c"><span class="mw-geshi cpp source-cpp">a <span class="sy1"><=></span> b</span></span> 执行且至少找到一个候选,比较未定义(<code>operator<=></code> 被定义为弃置的)。</li>
|
||||
<li>否则,如果 <span class="t-c"><span class="mw-geshi cpp source-cpp">R</span></span> 不是一个比较类别(见下文)或 <span class="t-c"><span class="mw-geshi cpp source-cpp">a <span class="sy1">==</span> b</span></span> 与 <span class="t-c"><span class="mw-geshi cpp source-cpp">a <span class="sy1"><</span> b</span></span> 有其一不可用,比较未定义(<code>operator<=></code> 被定义为弃置的)。</li>
|
||||
<li>否则,如果 <span class="t-c"><span class="mw-geshi cpp source-cpp">R</span></span> 是 <span class="t-c"><span class="mw-geshi cpp source-cpp">std<span class="sy4">::</span><span class="me2">strong_ordering</span></span></span>,结果是</li>
|
||||
</ul>
|
||||
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
||||
<div class="cpp source-cpp">
|
||||
<pre class="de1">a <span class="sy1">==</span> b <span class="sy4">?</span> R<span class="sy4">::</span><span class="me2">equal</span> <span class="sy4">:</span>
|
||||
a <span class="sy1"><</span> b <span class="sy4">?</span> R<span class="sy4">::</span><span class="me2">less</span> <span class="sy4">:</span>
|
||||
R<span class="sy4">::</span><span class="me2">greater</span></pre></div>
|
||||
</div>
|
||||
<ul>
|
||||
<li>否则,如果 <span class="t-c"><span class="mw-geshi cpp source-cpp">R</span></span> 是 <span class="t-c"><span class="mw-geshi cpp source-cpp">std<span class="sy4">::</span><span class="me2">weak_ordering</span></span></span>,结果是</li>
|
||||
</ul>
|
||||
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
||||
<div class="cpp source-cpp">
|
||||
<pre class="de1">a <span class="sy1">==</span> b <span class="sy4">?</span> R<span class="sy4">::</span><span class="me2">equivalent</span> <span class="sy4">:</span>
|
||||
a <span class="sy1"><</span> b <span class="sy4">?</span> R<span class="sy4">::</span><span class="me2">less</span> <span class="sy4">:</span>
|
||||
R<span class="sy4">::</span><span class="me2">greater</span></pre></div>
|
||||
</div>
|
||||
<ul>
|
||||
<li>否则(<span class="t-c"><span class="mw-geshi cpp source-cpp">R</span></span> 是 <span class="t-c"><span class="mw-geshi cpp source-cpp">std<span class="sy4">::</span><span class="me2">partial_ordering</span></span></span>),结果是</li>
|
||||
</ul>
|
||||
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
||||
<div class="cpp source-cpp">
|
||||
<pre class="de1">a <span class="sy1">==</span> b <span class="sy4">?</span> R<span class="sy4">::</span><span class="me2">equal</span> <span class="sy4">:</span>
|
||||
a <span class="sy1"><</span> b <span class="sy4">?</span> R<span class="sy4">::</span><span class="me2">less</span> <span class="sy4">:</span>
|
||||
b <span class="sy1"><</span> a <span class="sy4">?</span> R<span class="sy4">::</span><span class="me2">greater</span> <span class="sy4">:</span>
|
||||
R<span class="sy4">::</span><span class="me2">unordered</span></pre></div>
|
||||
</div>
|
||||
<p>与任何 <span class="t-c"><span class="mw-geshi cpp source-cpp">operator<span class="sy1"><=></span></span></span> 重载的规则一样,默认的 <code><=></code> 重载也允许类型被 <code><</code>,<code>></code>,<code><=</code>,和 <code>>=</code> 比较。</p>
|
||||
<p><br />
|
||||
如果 <span class="t-c"><span class="mw-geshi cpp source-cpp">operator<span class="sy1"><=></span></span></span> 是默认版本且 <span class="t-c"><span class="mw-geshi cpp source-cpp">operator<span class="sy1">==</span></span></span> 完全没有被声明,那么 <span class="t-c"><span class="mw-geshi cpp source-cpp">operator<span class="sy1">==</span></span></span> 将隐式地采用默认版本。</p>
|
||||
<div class="t-example">
|
||||
<div class="t-example-live-link"></div>
|
||||
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
||||
<div class="cpp source-cpp">
|
||||
<pre class="de1"><span class="co2">#include <compare></span>
|
||||
<span class="kw1">struct</span> Point <span class="br0">{</span>
|
||||
<span class="kw4">int</span> x<span class="sy4">;</span>
|
||||
<span class="kw4">int</span> y<span class="sy4">;</span>
|
||||
<span class="kw4">auto</span> operator<span class="sy1"><=></span><span class="br0">(</span><span class="kw4">const</span> Point<span class="sy3">&</span><span class="br0">)</span> <span class="kw4">const</span> <span class="sy1">=</span> <span class="kw1">default</span><span class="sy4">;</span>
|
||||
<span class="co1">// ... 非比较函数 ...</span>
|
||||
<span class="br0">}</span><span class="sy4">;</span>
|
||||
<span class="co1">// 编译器生成全部六个比较运算符</span>
|
||||
|
||||
<span class="co2">#include <iostream></span>
|
||||
<span class="co2">#include <set></span>
|
||||
<span class="kw4">int</span> main<span class="br0">(</span><span class="br0">)</span> <span class="br0">{</span>
|
||||
Point pt1<span class="br0">{</span><span class="nu0">1</span>, <span class="nu0">1</span><span class="br0">}</span>, pt2<span class="br0">{</span><span class="nu0">1</span>, <span class="nu0">2</span><span class="br0">}</span><span class="sy4">;</span>
|
||||
<a href="cpp-container-set.html"><span class="kw1277">std::<span class="me2">set</span></span></a><span class="sy1"><</span>Point<span class="sy1">></span> s<span class="sy4">;</span> <span class="co1">// ok</span>
|
||||
s.<span class="me1">insert</span><span class="br0">(</span>pt1<span class="br0">)</span><span class="sy4">;</span> <span class="co1">// ok</span>
|
||||
<a href="cpp-io-cout.html"><span class="kw1758">std::<span class="me2">cout</span></span></a> <span class="sy1"><<</span> <a href="cpp-io-manip-boolalpha.html"><span class="kw1764">std::<span class="me2">boolalpha</span></span></a>
|
||||
<span class="sy1"><<</span> <span class="br0">(</span>pt1 <span class="sy1">==</span> pt2<span class="br0">)</span> <span class="sy1"><<</span> <span class="st0">' '</span> <span class="co1">// false;operator== 隐式地采用默认版本</span>
|
||||
<span class="sy1"><<</span> <span class="br0">(</span>pt1 <span class="sy3">!</span><span class="sy1">=</span> pt2<span class="br0">)</span> <span class="sy1"><<</span> <span class="st0">' '</span> <span class="co1">// true</span>
|
||||
<span class="sy1"><<</span> <span class="br0">(</span>pt1 <span class="sy1"><</span> pt2<span class="br0">)</span> <span class="sy1"><<</span> <span class="st0">' '</span> <span class="co1">// true</span>
|
||||
<span class="sy1"><<</span> <span class="br0">(</span>pt1 <span class="sy1"><=</span> pt2<span class="br0">)</span> <span class="sy1"><<</span> <span class="st0">' '</span> <span class="co1">// true</span>
|
||||
<span class="sy1"><<</span> <span class="br0">(</span>pt1 <span class="sy1">></span> pt2<span class="br0">)</span> <span class="sy1"><<</span> <span class="st0">' '</span> <span class="co1">// false</span>
|
||||
<span class="sy1"><<</span> <span class="br0">(</span>pt1 <span class="sy1">>=</span> pt2<span class="br0">)</span> <span class="sy1"><<</span> <span class="st0">' '</span><span class="sy4">;</span><span class="co1">// false</span>
|
||||
<span class="br0">}</span></pre></div>
|
||||
</div>
|
||||
</div>
|
||||
<h4><span class="mw-headline" id=".E9.BB.98.E8.AE.A4.E7.9B.B8.E7.AD.89.E6.AF.94.E8.BE.83">默认相等比较</span></h4>
|
||||
<p>类可以定义 <span class="t-c"><span class="mw-geshi cpp source-cpp">operator<span class="sy1">==</span></span></span> 为默认版本,它返回一个 <span class="t-c"><span class="mw-geshi cpp source-cpp"><span class="kw4">bool</span></span></span> 值。这会以声明顺序对每个基类和成员子对象生成一轮相等比较。两个对象在它们每个基类和成员相等时相等。该检测会以声明顺序在找到基类或成员里出现不相等的情况下短路。</p>
|
||||
<p>与任何 <span class="t-c"><span class="mw-geshi cpp source-cpp">operator<span class="sy1">==</span></span></span> 重载的规则一样,不等测试也能被允许:</p>
|
||||
<div class="t-example">
|
||||
<div class="t-example-live-link"></div>
|
||||
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
||||
<div class="cpp source-cpp">
|
||||
<pre class="de1"><span class="kw1">struct</span> Point <span class="br0">{</span>
|
||||
<span class="kw4">int</span> x<span class="sy4">;</span>
|
||||
<span class="kw4">int</span> y<span class="sy4">;</span>
|
||||
<span class="kw4">bool</span> operator<span class="sy1">==</span><span class="br0">(</span><span class="kw4">const</span> Point<span class="sy3">&</span><span class="br0">)</span> <span class="kw4">const</span> <span class="sy1">=</span> <span class="kw1">default</span><span class="sy4">;</span>
|
||||
<span class="co1">// ... 非比较函数 ...</span>
|
||||
<span class="br0">}</span><span class="sy4">;</span>
|
||||
<span class="co1">// 编译器生成分成员的相等比较</span>
|
||||
|
||||
<span class="co2">#include <iostream></span>
|
||||
<span class="kw4">int</span> main<span class="br0">(</span><span class="br0">)</span> <span class="br0">{</span>
|
||||
Point pt1<span class="br0">{</span><span class="nu0">3</span>, <span class="nu0">5</span><span class="br0">}</span>, pt2<span class="br0">{</span><span class="nu0">2</span>, <span class="nu0">5</span><span class="br0">}</span><span class="sy4">;</span>
|
||||
<a href="cpp-io-cout.html"><span class="kw1758">std::<span class="me2">cout</span></span></a> <span class="sy1"><<</span> <a href="cpp-io-manip-boolalpha.html"><span class="kw1764">std::<span class="me2">boolalpha</span></span></a>
|
||||
<span class="sy1"><<</span> <span class="br0">(</span>pt1 <span class="sy3">!</span><span class="sy1">=</span> pt2<span class="br0">)</span> <span class="sy1"><<</span> <span class="st0">'<span class="es1">\n</span>'</span> <span class="co1">// true</span>
|
||||
<span class="sy1"><<</span> <span class="br0">(</span>pt1 <span class="sy1">==</span> pt1<span class="br0">)</span> <span class="sy1"><<</span> <span class="st0">'<span class="es1">\n</span>'</span><span class="sy4">;</span> <span class="co1">// true</span>
|
||||
<span class="kw1">struct</span> <span class="br0">[</span><span class="br0">[</span>maybe_unused<span class="br0">]</span><span class="br0">]</span> <span class="br0">{</span> <span class="kw4">int</span> x<span class="br0">{</span><span class="br0">}</span>, y<span class="br0">{</span><span class="br0">}</span><span class="sy4">;</span> <span class="br0">}</span> p, q<span class="sy4">;</span>
|
||||
<span class="co1">// if (p == q) { } // 错误:'operator==' 未被定义</span>
|
||||
<span class="br0">}</span></pre></div>
|
||||
</div>
|
||||
</div>
|
||||
<h4><span class="mw-headline" id=".E5.85.B6.E4.BB.96.E9.BB.98.E8.AE.A4.E6.AF.94.E8.BE.83.E6.93.8D.E4.BD.9C.E7.AC.A6">其他默认比较操作符</span></h4>
|
||||
<p>四个关系运算符(<code><</code>,<code>></code>,<code><=</code>,<code>>=</code>)均可以显式指定为默认版本。默认的关系运算符必须返回 <span class="t-c"><span class="mw-geshi cpp source-cpp"><span class="kw4">bool</span></span></span>。</p>
|
||||
<p>如果 <code>x <=> y</code> 的重载决议(包括参数交换后的 <code>operator<=></code>)失败,或 <code>operator@</code> 无法被应用到 <code>x <=> y</code> 的结果,该操作符是弃置的。否则,默认的 <code>operator@</code> 在重载决议选择参数顺序不变的 <code>operator<=></code> 时调用 <span class="t-c"><span class="mw-geshi cpp source-cpp">x <span class="sy1"><=></span> y @ <span class="nu0">0</span></span></span> ,否则调用 <span class="t-c"><span class="mw-geshi cpp source-cpp"><span class="nu0">0</span> @ y <span class="sy1"><=></span> x</span></span>:</p>
|
||||
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
||||
<div class="cpp source-cpp">
|
||||
<pre class="de1"><span class="kw1">struct</span> HasNoRelational <span class="br0">{</span><span class="br0">}</span><span class="sy4">;</span>
|
||||
|
||||
<span class="kw1">struct</span> C <span class="br0">{</span>
|
||||
<span class="kw1">friend</span> HasNoRelational operator<span class="sy1"><=></span><span class="br0">(</span><span class="kw4">const</span> C<span class="sy3">&</span>, <span class="kw4">const</span> C<span class="sy3">&</span><span class="br0">)</span><span class="sy4">;</span>
|
||||
<span class="kw4">bool</span> operator<span class="sy1"><</span><span class="br0">(</span><span class="kw4">const</span> C<span class="sy3">&</span><span class="br0">)</span> <span class="sy1">=</span> <span class="kw1">default</span><span class="sy4">;</span> <span class="co1">// OK:函数被弃置</span>
|
||||
<span class="br0">}</span><span class="sy4">;</span></pre></div>
|
||||
</div>
|
||||
<p>与此类似,<code>operator!=</code> 也可以显式指定为默认版本。如果 <code>x <=> y</code> 的重载决议失败,或 <code>x == y</code> 结果的类型不为 <span class="t-c"><span class="mw-geshi cpp source-cpp"><span class="kw4">bool</span></span></span>,它也会被弃置。默认的 <code>operator!=</code> 会根据重载决议的选择调用 <span class="t-c"><span class="mw-geshi cpp source-cpp"><span class="sy3">!</span><span class="br0">(</span>x <span class="sy1">==</span> y<span class="br0">)</span></span></span> 或者 <span class="t-c"><span class="mw-geshi cpp source-cpp"><span class="sy3">!</span><span class="br0">(</span>y <span class="sy1">==</span> x<span class="br0">)</span></span></span>。</p>
|
||||
<p>指定关系运算符使用默认版本可用于创建可取址的函数。其他场合仅需提供 <span class="t-c"><span class="mw-geshi cpp source-cpp">operator<span class="sy1"><=></span></span></span> 和 <span class="t-c"><span class="mw-geshi cpp source-cpp">operator<span class="sy1">==</span></span></span>。</p>
|
||||
<h3><span class="mw-headline" id=".E8.87.AA.E5.AE.9A.E4.B9.89.E7.9A.84.E6.AF.94.E8.BE.83.E5.92.8C.E6.AF.94.E8.BE.83.E7.B1.BB.E5.88.AB">自定义的比较和比较类别</span></h3>
|
||||
<p>在默认语义不适用的情况下,例如成员不能按顺序比较,或者不能采用自然比较,那么程序员可以自定义 <span class="t-c"><span class="mw-geshi cpp source-cpp">operator<span class="sy1"><=></span></span></span> 并让编译器生成合适的比较运算符。比较运算符的种类由用户定义的 <span class="t-c"><span class="mw-geshi cpp source-cpp">operator<span class="sy1"><=></span></span></span> 决定。</p>
|
||||
<p>返回类型有三种:</p>
|
||||
<table class="wikitable" style="font-size:85%; text-align:center;">
|
||||
<tr>
|
||||
<th>返回类型</th>
|
||||
<th>运算符</th>
|
||||
<th>等价的值</th>
|
||||
<th>无法比较的值</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="cpp-utility-compare-strong_ordering.html"><tt>std::strong_ordering</tt></a></td>
|
||||
<td>== != < > <= >=</td>
|
||||
<td>不可以被区分</td>
|
||||
<td>不允许比较</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="cpp-utility-compare-weak_ordering.html"><tt>std::weak_ordering</tt></a></td>
|
||||
<td>== != < > <= >=</td>
|
||||
<td>可以被区分</td>
|
||||
<td>不允许比较</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="cpp-utility-compare-partial_ordering.html"><tt>std::partial_ordering</tt></a></td>
|
||||
<td>== != < > <= >=</td>
|
||||
<td>可以被区分</td>
|
||||
<td>允许比较</td>
|
||||
</tr>
|
||||
</table>
|
||||
<h4><span class="mw-headline" id=".E5.BC.BA.E5.BA.8F">强序</span></h4>
|
||||
<p>在这个自定义 <code>operator<=></code> 返回 <a href="cpp-utility-compare-strong_ordering.html"><tt>std::strong_ordering</tt></a> 的例子中,该操作符比较了类的每个成员,只是顺序不同(在这里名在姓前面比较)。</p>
|
||||
<div class="t-example">
|
||||
<div class="t-example-live-link"></div>
|
||||
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
||||
<div class="cpp source-cpp">
|
||||
<pre class="de1"><span class="co2">#include <compare></span>
|
||||
<span class="co2">#include <string></span>
|
||||
<span class="kw1">struct</span> Base <span class="br0">{</span>
|
||||
<a href="cpp-string-basic_string.html"><span class="kw1230">std::<span class="me2">string</span></span></a> zip<span class="sy4">;</span>
|
||||
<span class="kw4">auto</span> operator<span class="sy1"><=></span><span class="br0">(</span><span class="kw4">const</span> Base<span class="sy3">&</span><span class="br0">)</span> <span class="kw4">const</span> <span class="sy1">=</span> <span class="kw1">default</span><span class="sy4">;</span>
|
||||
<span class="br0">}</span><span class="sy4">;</span>
|
||||
<span class="kw1">struct</span> TotallyOrdered <span class="sy4">:</span> Base <span class="br0">{</span>
|
||||
<a href="cpp-string-basic_string.html"><span class="kw1230">std::<span class="me2">string</span></span></a> tax_id<span class="sy4">;</span>
|
||||
<a href="cpp-string-basic_string.html"><span class="kw1230">std::<span class="me2">string</span></span></a> first_name<span class="sy4">;</span>
|
||||
<a href="cpp-string-basic_string.html"><span class="kw1230">std::<span class="me2">string</span></span></a> last_name<span class="sy4">;</span>
|
||||
<span class="kw1">public</span><span class="sy4">:</span>
|
||||
<span class="co1">// 自定义 operator<=> ,因为我们希望(在比较姓前)先比较名:</span>
|
||||
std<span class="sy4">::</span><span class="me2">strong_ordering</span> operator<span class="sy1"><=></span><span class="br0">(</span><span class="kw4">const</span> TotallyOrdered<span class="sy3">&</span> that<span class="br0">)</span> <span class="kw4">const</span> <span class="br0">{</span>
|
||||
<span class="kw1">if</span> <span class="br0">(</span><span class="kw4">auto</span> cmp <span class="sy1">=</span> <span class="br0">(</span>Base<span class="sy3">&</span><span class="br0">)</span><span class="br0">(</span><span class="sy2">*</span>this<span class="br0">)</span> <span class="sy1"><=></span> <span class="br0">(</span>Base<span class="sy3">&</span><span class="br0">)</span>that<span class="sy4">;</span> cmp <span class="sy3">!</span><span class="sy1">=</span> <span class="nu0">0</span><span class="br0">)</span>
|
||||
<span class="kw1">return</span> cmp<span class="sy4">;</span>
|
||||
<span class="kw1">if</span> <span class="br0">(</span><span class="kw4">auto</span> cmp <span class="sy1">=</span> last_name <span class="sy1"><=></span> that.<span class="me1">last_name</span><span class="sy4">;</span> cmp <span class="sy3">!</span><span class="sy1">=</span> <span class="nu0">0</span><span class="br0">)</span>
|
||||
<span class="kw1">return</span> cmp<span class="sy4">;</span>
|
||||
<span class="kw1">if</span> <span class="br0">(</span><span class="kw4">auto</span> cmp <span class="sy1">=</span> first_name <span class="sy1"><=></span> that.<span class="me1">first_name</span><span class="sy4">;</span> cmp <span class="sy3">!</span><span class="sy1">=</span> <span class="nu0">0</span><span class="br0">)</span>
|
||||
<span class="kw1">return</span> cmp<span class="sy4">;</span>
|
||||
<span class="kw1">return</span> tax_id <span class="sy1"><=></span> that.<span class="me1">tax_id</span><span class="sy4">;</span>
|
||||
<span class="br0">}</span>
|
||||
<span class="co1">// ... 非比较函数 ...</span>
|
||||
<span class="br0">}</span><span class="sy4">;</span>
|
||||
<span class="co1">// 编译器生成全部四个关系运算符</span>
|
||||
|
||||
<span class="co2">#include <cassert></span>
|
||||
<span class="co2">#include <set></span>
|
||||
<span class="kw4">int</span> main<span class="br0">(</span><span class="br0">)</span> <span class="br0">{</span>
|
||||
TotallyOrdered to1<span class="br0">{</span><span class="st0">"a"</span>,<span class="st0">"b"</span>,<span class="st0">"c"</span>,<span class="st0">"d"</span><span class="br0">}</span>, to2<span class="br0">{</span><span class="st0">"a"</span>,<span class="st0">"b"</span>,<span class="st0">"d"</span>,<span class="st0">"c"</span><span class="br0">}</span><span class="sy4">;</span>
|
||||
<a href="cpp-container-set.html"><span class="kw1277">std::<span class="me2">set</span></span></a><span class="sy1"><</span>TotallyOrdered<span class="sy1">></span> s<span class="sy4">;</span> <span class="co1">// OK</span>
|
||||
s.<span class="me1">insert</span><span class="br0">(</span>to1<span class="br0">)</span><span class="sy4">;</span> <span class="co1">// OK</span>
|
||||
<a href="cpp-error-assert.html"><span class="kw774">assert</span></a><span class="br0">(</span>to2 <span class="sy1"><=</span> to1<span class="br0">)</span><span class="sy4">;</span> <span class="co1">// OK,调用 <=> 一次</span>
|
||||
<span class="br0">}</span></pre></div>
|
||||
</div>
|
||||
</div>
|
||||
<p>注:返回 <a href="cpp-utility-compare-strong_ordering.html"><tt>std::strong_ordering</tt></a> 的操作符需要比较每个成员,因为如果有成员没有被比较,可替换性会受牵连:两个可被区分的值有可能会比较相等。</p>
|
||||
<h4><span class="mw-headline" id=".E5.BC.B1.E5.BA.8F">弱序</span></h4>
|
||||
<p>在这个自定义 <code>operator<=></code> 返回 <a href="cpp-utility-compare-weak_ordering.html"><tt>std::weak_ordering</tt></a> 的例子中,该操作符不分大小写地比较了类的字符串成员:这和默认比较不同(因此需要自定义运算符)且通过这种方式比较相等的两个字符串可能可以被区分。</p>
|
||||
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
||||
<div class="cpp source-cpp">
|
||||
<pre class="de1"><span class="kw1">class</span> CaseInsensitiveString <span class="br0">{</span>
|
||||
<a href="cpp-string-basic_string.html"><span class="kw1230">std::<span class="me2">string</span></span></a> s<span class="sy4">;</span>
|
||||
<span class="kw1">public</span><span class="sy4">:</span>
|
||||
std<span class="sy4">::</span><span class="me2">weak_ordering</span> operator<span class="sy1"><=></span><span class="br0">(</span><span class="kw4">const</span> CaseInsensitiveString<span class="sy3">&</span> b<span class="br0">)</span> <span class="kw4">const</span> <span class="br0">{</span>
|
||||
<span class="kw1">return</span> case_insensitive_compare<span class="br0">(</span>s.<span class="me1">c_str</span><span class="br0">(</span><span class="br0">)</span>, b.<span class="me1">s</span>.<span class="me1">c_str</span><span class="br0">(</span><span class="br0">)</span><span class="br0">)</span><span class="sy4">;</span>
|
||||
<span class="br0">}</span>
|
||||
std<span class="sy4">::</span><span class="me2">weak_ordering</span> operator<span class="sy1"><=></span><span class="br0">(</span><span class="kw4">const</span> <span class="kw4">char</span><span class="sy2">*</span> b<span class="br0">)</span> <span class="kw4">const</span> <span class="br0">{</span>
|
||||
<span class="kw1">return</span> case_insensitive_compare<span class="br0">(</span>s.<span class="me1">c_str</span><span class="br0">(</span><span class="br0">)</span>, b<span class="br0">)</span><span class="sy4">;</span>
|
||||
<span class="br0">}</span>
|
||||
<span class="co1">// ... 非比较函数 ...</span>
|
||||
<span class="br0">}</span><span class="sy4">;</span>
|
||||
|
||||
<span class="co1">// 编译器生成全部四个关系运算符</span>
|
||||
CaseInsensitiveString cis1, cis2<span class="sy4">;</span>
|
||||
<a href="cpp-container-set.html"><span class="kw1277">std::<span class="me2">set</span></span></a><span class="sy1"><</span>CaseInsensitiveString<span class="sy1">></span> s<span class="sy4">;</span> <span class="co1">// OK</span>
|
||||
s.<span class="me1">insert</span><span class="br0">(</span><span class="coMULTI">/*...*/</span><span class="br0">)</span><span class="sy4">;</span> <span class="co1">// ok</span>
|
||||
<span class="kw1">if</span> <span class="br0">(</span>cis1 <span class="sy1"><=</span> cis2<span class="br0">)</span> <span class="br0">{</span> <span class="coMULTI">/*...*/</span> <span class="br0">}</span> <span class="co1">// OK,执行一次比较操作</span>
|
||||
|
||||
<span class="co1">// 编译器也生成了全部八个混合参数的关系运算符</span>
|
||||
<span class="kw1">if</span> <span class="br0">(</span>cis1 <span class="sy1"><=</span> <span class="st0">"xyzzy"</span><span class="br0">)</span> <span class="br0">{</span> <span class="coMULTI">/*...*/</span> <span class="br0">}</span> <span class="co1">// OK,执行一次比较操作</span>
|
||||
<span class="kw1">if</span> <span class="br0">(</span><span class="st0">"xyzzy"</span> <span class="sy1">>=</span> cis1<span class="br0">)</span> <span class="br0">{</span> <span class="coMULTI">/*...*/</span> <span class="br0">}</span> <span class="co1">// OK,语义相同</span></pre></div>
|
||||
</div>
|
||||
<p>注:这个例子展示了参数类型不同的 <code>operator<=></code> 的效果:它生成了双向的不同类型参数的比较。</p>
|
||||
<h4><span class="mw-headline" id=".E5.81.8F.E5.BA.8F">偏序</span></h4>
|
||||
<p>偏序是一种允许无法比较(无序)的值的比较的排序,比如包括 NaN 值的浮点排序,或在这个例子里的没有关联的人:</p>
|
||||
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
||||
<div class="cpp source-cpp">
|
||||
<pre class="de1"><span class="kw1">class</span> PersonInFamilyTree <span class="br0">{</span> <span class="co1">// ...</span>
|
||||
<span class="kw1">public</span><span class="sy4">:</span>
|
||||
std<span class="sy4">::</span><span class="me2">partial_ordering</span> operator<span class="sy1"><=></span><span class="br0">(</span><span class="kw4">const</span> PersonInFamilyTree<span class="sy3">&</span> that<span class="br0">)</span> <span class="kw4">const</span> <span class="br0">{</span>
|
||||
<span class="kw1">if</span> <span class="br0">(</span>this<span class="sy2">-</span><span class="sy1">></span>is_the_same_person_as <span class="br0">(</span> that<span class="br0">)</span><span class="br0">)</span> <span class="kw1">return</span> partial_ordering<span class="sy4">::</span><span class="me2">equivalent</span><span class="sy4">;</span>
|
||||
<span class="kw1">if</span> <span class="br0">(</span>this<span class="sy2">-</span><span class="sy1">></span>is_transitive_child_of<span class="br0">(</span> that<span class="br0">)</span><span class="br0">)</span> <span class="kw1">return</span> partial_ordering<span class="sy4">::</span><span class="me2">less</span><span class="sy4">;</span>
|
||||
<span class="kw1">if</span> <span class="br0">(</span>that. <span class="me1">is_transitive_child_of</span><span class="br0">(</span><span class="sy2">*</span>this<span class="br0">)</span><span class="br0">)</span> <span class="kw1">return</span> partial_ordering<span class="sy4">::</span><span class="me2">greater</span><span class="sy4">;</span>
|
||||
<span class="kw1">return</span> partial_ordering<span class="sy4">::</span><span class="me2">unordered</span><span class="sy4">;</span>
|
||||
<span class="br0">}</span>
|
||||
<span class="co1">// ... 非比较函数 ...</span>
|
||||
<span class="br0">}</span><span class="sy4">;</span>
|
||||
<span class="co1">// 编译器生成全部四个关系运算符</span>
|
||||
PersonInFamilyTree per1, per2<span class="sy4">;</span>
|
||||
<span class="kw1">if</span> <span class="br0">(</span>per1 <span class="sy1"><</span> per2<span class="br0">)</span> <span class="br0">{</span> <span class="coMULTI">/*...*/</span> <span class="br0">}</span> <span class="co1">// OK,per2 是 per1 的先人</span>
|
||||
<span class="kw1">else</span> <span class="kw1">if</span> <span class="br0">(</span>per1 <span class="sy1">></span> per2<span class="br0">)</span> <span class="br0">{</span> <span class="coMULTI">/*...*/</span> <span class="br0">}</span> <span class="co1">// OK,per1 是 per2 的先人</span>
|
||||
<span class="kw1">else</span> <span class="kw1">if</span> <span class="br0">(</span>std<span class="sy4">::</span><span class="me2">is_eq</span><span class="br0">(</span>per1 <span class="sy1"><=></span> per2<span class="br0">)</span><span class="br0">)</span> <span class="br0">{</span> <span class="coMULTI">/*...*/</span> <span class="br0">}</span> <span class="co1">// OK,per1 是 per2(同一人)</span>
|
||||
<span class="kw1">else</span> <span class="br0">{</span> <span class="coMULTI">/*...*/</span> <span class="br0">}</span> <span class="co1">// per1 与 per2 没有(直系)关联</span>
|
||||
<span class="kw1">if</span> <span class="br0">(</span>per1 <span class="sy1"><=</span> per2<span class="br0">)</span> <span class="br0">{</span> <span class="coMULTI">/*...*/</span> <span class="br0">}</span> <span class="co1">// OK,per2 是 per1 或 per1 的先人</span>
|
||||
<span class="kw1">if</span> <span class="br0">(</span>per1 <span class="sy1">>=</span> per2<span class="br0">)</span> <span class="br0">{</span> <span class="coMULTI">/*...*/</span> <span class="br0">}</span> <span class="co1">// OK,per1 是 per2 或 per2 的先人</span>
|
||||
<span class="kw1">if</span> <span class="br0">(</span>std<span class="sy4">::</span><span class="me2">is_neq</span><span class="br0">(</span>per1 <span class="sy1"><=></span> per2<span class="br0">)</span><span class="br0">)</span> <span class="br0">{</span> <span class="coMULTI">/*...*/</span> <span class="br0">}</span> <span class="co1">// OK,per1 不是 per2(但可能有直系关联)</span></pre></div>
|
||||
</div>
|
||||
<h3><span class="mw-headline" id=".E5.8F.82.E9.98.85">参阅</span></h3>
|
||||
<ul>
|
||||
<li>调用重载运算符中的<a href="cpp-language-overload_resolution.html#.E8.B0.83.E7.94.A8.E9.87.8D.E8.BD.BD.E8.BF.90.E7.AE.97.E7.AC.A6">重载决议</a></li>
|
||||
<li>内建的<a href="cpp-language-operator_comparison.html#.E4.B8.89.E8.B7.AF.E6.AF.94.E8.BE.83">三路比较运算符</a></li>
|
||||
<li>比较运算符的<a href="cpp-language-operators.html#.E6.AF.94.E8.BE.83.E8.BF.90.E7.AE.97.E7.AC.A6">运算符重载</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="visualClear"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user